<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Probe - AI-Native Code Understanding</title>
	<!-- Add Marked.js for Markdown rendering -->
	<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
	<!-- Add Highlight.js for syntax highlighting -->
	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/github.min.css">
	<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
	<!-- Add Mermaid.js for diagram rendering -->
	<script src="https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js"></script>
	<style>
		body {
			font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
			margin: 0;
			padding: 0;
			line-height: 1.5;
			color: #333;
			min-height: 100vh;
			overflow-x: hidden;
			overflow-y: auto;
		}

		#chat-container {
			max-width: 868px;
			/* 900px - 16px padding on each side */
			margin: 0 auto;
			display: flex;
			flex-direction: column;
			min-height: 100vh;
			/* Changed from height to min-height to allow expansion */
			position: relative;
			box-sizing: border-box;
		}

		.header {
			padding: 10px 0;
			border-bottom: 1px solid #eee;
			display: block; /* Ensure header is visible by default */
		}

		.header-container {
			display: flex;
			justify-content: space-between;
			align-items: center;
		}

		.header-left {
			display: flex;
			align-items: center;
		}

		.header-logo {
			height: 30px;
			margin-right: 10px;
		}
		
		.header-left a {
			text-decoration: none;
			display: inline-block;
		}
		
		.header-left a:hover .header-logo {
			opacity: 0.8;
			transition: opacity 0.2s ease;
		}

		.new-chat-link {
			font-size: 15px;
			color: #555;
			text-decoration: none;
			font-weight: 500;
			padding: 5px 10px;
			border: 1px solid #ddd;
			border-radius: 4px;
			margin-left: 5px;
			transition: all 0.2s ease;
		}

		.new-chat-link:hover {
			background-color: #f5f5f5;
			border-color: #ccc;
		}

		/* History dropdown styles */
		.history-dropdown {
			position: relative;
			display: inline-block;
			margin-right: 5px;
		}

		.history-button {
			font-size: 15px;
			color: #555;
			background: none;
			border: 1px solid #ddd;
			border-radius: 4px;
			padding: 5px 10px;
			cursor: pointer;
			display: flex;
			align-items: center;
			gap: 5px;
			font-weight: 500;
			transition: all 0.2s ease;
		}

		.history-button:hover {
			background-color: #f5f5f5;
			border-color: #ccc;
		}

		.history-button svg {
			width: 16px;
			height: 16px;
		}

		.history-dropdown-menu {
			position: absolute;
			top: 100%;
			left: 0;
			background: white;
			border: 1px solid #ddd;
			border-radius: 6px;
			box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
			z-index: 1000;
			min-width: 320px;
			max-width: 400px;
			max-height: 400px;
			overflow-y: auto;
			display: none;
			margin-top: 2px;
		}

		.history-dropdown-menu.show {
			display: block;
		}

		.history-dropdown-header {
			padding: 12px 16px 8px;
			font-size: 14px;
			font-weight: 600;
			color: #333;
			border-bottom: 1px solid #eee;
		}

		.history-loading {
			padding: 16px;
			text-align: center;
			color: #666;
			font-size: 14px;
		}

		.history-empty {
			padding: 16px;
			text-align: center;
			color: #666;
			font-size: 14px;
		}

		.history-list {
			padding: 8px 0;
		}

		.history-item {
			padding: 12px 16px;
			cursor: pointer;
			border-bottom: 1px solid #f5f5f5;
			transition: background-color 0.2s ease;
		}

		.history-item:last-child {
			border-bottom: none;
		}

		.history-item:hover {
			background-color: #f8f9fa;
		}

		.history-item-preview {
			font-size: 14px;
			color: #333;
			margin-bottom: 4px;
			line-height: 1.4;
			display: -webkit-box;
			-webkit-line-clamp: 2;
			-webkit-box-orient: vertical;
			overflow: hidden;
		}

		.history-item-meta {
			font-size: 12px;
			color: #666;
			display: flex;
			justify-content: space-between;
			align-items: center;
		}

		.history-item-time {
			font-size: 11px;
		}

		.history-item-count {
			font-size: 11px;
			background: #e9ecef;
			padding: 2px 6px;
			border-radius: 10px;
		}

		#messages {
			flex: 1;
			background-color: #fff;
			/* Removed overflow-y: auto to let the page handle scrolling */
			margin-bottom: 80px;
			/* Keep margin for fixed input form */
			margin-top: 20px;
			/* Space for fixed input form */
		}

		.tool-call {
			margin: 10px 0;
			border: 1px solid #ddd;
			border-radius: 8px;
			background-color: #f8f9fa;
			overflow: hidden;
			box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
			transition: all 0.2s ease;
		}

		.tool-call:hover {
			box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
		}

		.tool-call-header {
			background-color: #e9ecef;
			padding: 10px 14px;
			font-weight: bold;
			border-bottom: 1px solid #ddd;
			display: flex;
			justify-content: space-between;
			align-items: center;
		}

		.tool-call-name {
			color: #0066cc;
			font-size: 1.05em;
		}

		.tool-call-timestamp {
			font-size: 0.8em;
			color: #666;
			font-style: italic;
		}

		.tool-call-content {
			padding: 12px;
		}

		.tool-call-description {
			background-color: #ffffff;
			padding: 10px 12px;
			border-radius: 6px;
			border-left: 3px solid #44CDF3;
			margin-bottom: 10px;
			font-size: 0.95em;
			color: #333;
		}

		.tool-call-args {
			background-color: #ffffff;
			padding: 10px;
			border-radius: 6px;
			border: 1px solid #eee;
			font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
			font-size: 0.9em;
			margin-bottom: 10px;
			white-space: pre-wrap;
		}

		.tool-call-result {
			background-color: #f0f8ff;
			padding: 10px;
			border-radius: 6px;
			border: 1px solid #e0e8ff;
			font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
			font-size: 0.9em;
			white-space: pre-wrap;
			max-height: 300px;
			overflow-y: auto;
		}


		#input-form {
			position: fixed;
			display: flex;
			padding: 16px 0;
			background-color: white;
			border-top: 1px solid #ddd;
			z-index: 100;
			max-width: 868px;
			width: calc(100% - 32px);
			margin: 0 auto;
			left: 50%;
			transform: translateX(-50%);
			box-sizing: border-box;
			align-items: flex-end;
			/* Align items to the bottom */
		}

		#input-form.centered {
			top: 50%;
			transform: translate(-50%, -50%);
			border-top: none;
		}

		.centered-logo-container {
			text-align: center;
			margin-bottom: 20px;
			position: fixed;
			top: 35%;
			left: 50%;
			transform: translate(-50%, -100%);
			z-index: 99;
		}

		.api-setup-mode .centered-logo-container {
			position: static;
			margin: 40px auto 20px;
			width: 100%;
			max-width: 800px;
			transform: none;
		}

		.centered-logo-container h1 {
			font-weight: 300;
			display: flex;
			align-items: center;
			justify-content: center;
			margin: 0;
		}

		.centered-logo-container h1 img {
			height: 80px;
			margin-right: 16px;
		}

		.centered-logo-container h1 {
			font-size: 38px;
		}

		#input-form.bottom {
			bottom: 0;
		}

		.search-suggestions {
			color: #999;
			font-size: 0.85em;
			display: none;
			text-align: left;
			padding: 0;
			position: fixed;
			max-width: 868px;
			width: calc(100% - 32px);
			margin: 0 auto;
			background-color: white;
			left: 50%;
			transform: translateX(-50%);
			z-index: 99;
		}

		.search-suggestions ul {
			list-style: none;
			padding: 0;
			margin: 0;
			display: flex;
			flex-wrap: wrap;
		}

		.search-suggestions li {
			padding: 6px 16px 6px 0;
			white-space: nowrap;
			cursor: pointer;
		}

		.search-suggestions li:hover {
			color: #44CDF3;
		}

		#input-form.centered .search-suggestions {
			display: block;
		}

		.folder-info {
			color: #666;
			font-size: 0.9em;
			margin-top: 10px;
			padding-top: 10px;
			border-top: 1px solid #e0e0e0;
			font-style: italic;
			font-weight: 500;
		}

		#input-form.centered .folder-info {
			display: block;
		}


		#message-input {
			resize: none;
			flex: 1;
			padding: 12px 40px 12px 16px;
			border: 1px solid #ddd;
			border-radius: 8px;
			font-size: 14px;
			box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
			resize: none;
			overflow-y: auto;
			height: 1.5em;
			width: 100%;
			box-sizing: border-box;
			/* Changed from 44px to auto */
			min-height: 44px;
			/* Ensures 1 row minimum */
			max-height: 200px;
			/* Limits to ~10 rows */
			line-height: 1.5em;

			box-sizing: border-box;
		}

		button {
			padding: 12px 24px;
			margin-left: 10px;
			background-color: #44CDF3;
			color: white;
			border: none;
			border-radius: 8px;
			cursor: pointer;
			font-weight: bold;
			font-size: 18px;
			box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
			transition: all 0.2s ease;
			align-self: flex-end;
			/* Ensure button aligns to bottom */
			height: 44px;
			/* Match the height of the single-line textarea */
		}

		button:hover {
			background-color: #2bb5db;
		}

		#search-button {
			padding: 12px 20px;
			background-color: #44CDF3;
			color: white;
			border: none;
			border-radius: 8px;
			cursor: pointer;
			font-weight: 500;
			transition: all 0.2s ease;
			white-space: nowrap;
			flex-shrink: 0;
			align-self: flex-start;
			margin-left: 0;
			height: auto;
		}


		#folder-list ul {
			margin: 4px 0;
			padding-left: 20px;
		}

		#folder-list li {
			padding: 2px 0;
		}

		#folder-list strong {
			color: #333;
			font-weight: 600;
		}

		.footer {
			text-align: center;
			padding: 10px;
			font-size: 14px;
			color: #666;
			position: fixed;
			bottom: 0;
			left: 0;
			right: 0;
			background-color: white;
			border-top: 1px solid #eee;
			z-index: 50;
		}

		.footer a {
			color: #2196F3;
			text-decoration: none;
		}

		.footer a:hover {
			text-decoration: underline;
		}

		.header-container {
			display: flex;
			align-items: center;
			justify-content: space-between;
		}

		.example {
			font-style: italic;
			color: #666;
			margin: 8px 0;
		}

		/* Markdown styling */
		.markdown-content {
			line-height: 1.6;
		}

		.markdown-content h1,
		.markdown-content h2,
		.markdown-content h3 {
			margin-top: 24px;
			margin-bottom: 16px;
			font-weight: 600;
			line-height: 1.25;
		}

		.markdown-content h1 {
			font-size: 2em;
		}

		.markdown-content h2 {
			font-size: 1.5em;
		}

		.markdown-content h3 {
			font-size: 1.25em;
		}

		.markdown-content p,
		.markdown-content ul,
		.markdown-content ol {
			margin-top: 0;
			margin-bottom: 16px;
		}

		.markdown-content code {
			padding: 0.2em 0.4em;
			margin: 0;
			font-size: 85%;
			background-color: rgba(27, 31, 35, 0.05);
			border-radius: 3px;
			font-family: SFMono-Regular, Consolas, Liberation Mono, Menlo, monospace;
		}

		.markdown-content pre {
			padding: 16px;
			overflow: auto;
			font-size: 85%;
			line-height: 1.45;
			background-color: #f6f8fa;
			border-radius: 3px;
			margin-top: 0;
			margin-bottom: 16px;
		}

		.markdown-content pre code {
			padding: 0;
			margin: 0;
			font-size: 100%;
			background-color: transparent;
			border: 0;
		}

		.user-message {
			background-color: #f1f1f1;
			padding: 10px 14px;
			border-radius: 18px;
			margin-bottom: 6px;
			max-width: 80%;
			align-self: flex-end;
			font-weight: 500;
		}

		.ai-message {
			background-color: transparent;
			padding: 10px 14px;
			margin-bottom: 4px;
			max-width: 90%;
			align-self: flex-start;
		}

		.message-container {
			display: flex;
			flex-direction: column;
		}

		.copy-button-container {
			align-self: flex-start;
			margin-bottom: 12px;
			margin-top: -20px;
		}

		.copy-button {
			background-color: white;
			border-radius: 4px;
			padding: 4px 8px;
			cursor: pointer;
			font-size: 12px;
			color: #666;
			display: flex;
			align-items: center;
			border: none;
		}

		.copy-button:hover {
			background-color: #d0d0d0;
		}

		.copy-button svg {
			width: 16px;
			height: 16px;
			margin-right: 4px;
		}

		.message-container {
			display: flex;
			flex-direction: column;
		}

		/* Mermaid diagram styling */
		.mermaid {
			background-color: #f8f9fa;
			padding: 16px;
			border-radius: 8px;
			margin: 16px 0;
			overflow-x: auto;
			text-align: center;
			position: relative;
		}

		.mermaid svg,
		.mermaid-png {
			max-width: 100%;
			height: auto;
			transition: transform 0.2s ease;
		}

		/* Zoom icon overlay */
		.mermaid-container {
			position: relative;
			display: inline-block;
		}

		.zoom-icon {
			position: absolute;
			top: 10px;
			right: 10px;
			background-color: rgba(255, 255, 255, 0.8);
			border-radius: 50%;
			width: 32px;
			height: 32px;
			display: flex;
			align-items: center;
			justify-content: center;
			cursor: pointer;
			opacity: 0;
			transition: opacity 0.2s ease;
			box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
			z-index: 10;
		}

		.mermaid-container:hover .zoom-icon {
			opacity: 1;
		}

		.zoom-icon svg {
			width: 18px;
			height: 18px;
		}

		/* Fullscreen dialog */
		.diagram-dialog {
			position: fixed;
			top: 0;
			left: 0;
			width: 100%;
			height: 100%;
			background-color: rgba(0, 0, 0, 0.85);
			display: flex;
			align-items: center;
			justify-content: center;
			z-index: 1000;
			padding: 40px;
			box-sizing: border-box;
			opacity: 0;
			pointer-events: none;
			transition: opacity 0.3s ease;
			overflow: hidden;
			/* Prevent any scrolling */
		}

		.diagram-dialog.active {
			opacity: 1;
			pointer-events: auto;
		}

		.diagram-dialog-content {
			max-width: 90%;
			max-height: 90%;
			background-color: white;
			border-radius: 8px;
			padding: 20px;
			position: relative;
			display: flex;
			align-items: center;
			justify-content: center;
			overflow: hidden;
			/* Prevent scrollbars */
		}

		.diagram-dialog img,
		.diagram-dialog svg {
			max-width: 100%;
			max-height: 100%;
			object-fit: contain;
			/* Ensure image fits while maintaining aspect ratio */
			display: block;
		}

		.close-dialog {
			position: absolute;
			top: 10px;
			right: 10px;
			background-color: rgba(255, 255, 255, 0.8);
			border-radius: 50%;
			width: 36px;
			height: 36px;
			display: flex;
			align-items: center;
			justify-content: center;
			cursor: pointer;
			box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
			z-index: 1001;
		}

		.close-dialog svg {
			width: 20px;
			height: 20px;
		}

		/* Token usage display styles */
		.token-usage {
			position: fixed;
			bottom: 80px;
			right: 20px;
			background-color: rgba(255, 255, 255, 0.95);
			border: 1px solid #ddd;
			border-radius: 8px;
			padding: 10px 14px;
			font-size: 12px;
			color: #666;
			box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
			z-index: 100;
			display: none;
			/* Hidden by default, shown after first message */
		}

		.token-usage-content {
			display: flex;
			flex-direction: column;
			gap: 6px;
		}

		.token-usage-table {
			display: table;
			width: 100%;
			border-collapse: collapse;
		}

		.token-usage-row {
			display: table-row;
		}

		.token-label {
			display: table-cell;
			font-weight: bold;
			color: #444;
			padding-right: 10px;
			text-align: left;
			white-space: nowrap;
		}

		.token-value {
			display: table-cell;
			text-align: right;
			white-space: nowrap;
		}

		.cache-info {
			color: #888;
			font-size: 11px;
			margin-left: 5px;
		}

		/* New minimal image upload styles */
		.input-wrapper {
			display: flex;
			align-items: flex-start;
			gap: 8px;
			width: 100%;
		}

		.textarea-container {
			position: relative;
			flex: 1;
			display: flex;
			align-items: flex-start;
		}

		#message-input {
			flex: 1;
			min-height: 40px;
			padding-right: 40px; /* Make space for upload icon */
		}

		.image-upload-icon {
			position: absolute;
			right: 12px;
			top: 50%;
			transform: translateY(-50%);
			width: 24px;
			height: 24px;
			background: none !important;
			border: none !important;
			cursor: pointer;
			color: #999 !important;
			padding: 4px !important;
			border-radius: 4px !important;
			transition: all 0.2s ease;
			display: flex;
			align-items: center;
			justify-content: center;
			z-index: 10;
			margin: 0 !important;
			font-size: inherit !important;
			font-weight: normal !important;
			box-shadow: none !important;
		}

		.image-upload-icon:hover {
			color: #666 !important;
			background-color: rgba(0, 0, 0, 0.05) !important;
		}

		.image-upload-icon svg {
			width: 16px;
			height: 16px;
		}

		/* Floating thumbnails */
		.floating-thumbnails {
			display: flex;
			flex-wrap: wrap;
			gap: 8px;
			margin-bottom: 8px;
			padding: 0;
			position: absolute;
			bottom: 100%;
			left: 0;
			right: 0;
			z-index: 101;
			justify-content: flex-start;
		}

		.floating-thumbnail {
			position: relative;
			width: 60px;
			height: 60px;
		}

		.floating-thumbnail img {
			width: 100%;
			height: 100%;
			object-fit: cover;
			border-radius: 6px;
			border: 1px solid #e0e0e0;
			box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
		}

		.floating-thumbnail-remove {
			position: absolute;
			top: 0px;
			right: -16px;
			width: 16px;
			height: 16px;
			background: none !important;
			color: #000;
			border: none;
			cursor: pointer;
			font-size: 12px;
			font-weight: bold;
			display: flex;
			align-items: center;
			justify-content: center;
			line-height: 1;
			transition: opacity 0.2s ease;
			opacity: 0.6;
			text-shadow: 0 0 2px rgba(255, 255, 255, 0.8);
		}

		.floating-thumbnail-remove:hover {
			opacity: 1;
		}

		/* Drag and drop styles */
		.textarea-container.drag-over textarea {
			background-color: #e3f2fd;
			border-color: #2196f3;
		}

		/* Image display in messages */
		.user-message img,
		.ai-message img {
			max-width: 100%;
			max-height: 300px;
			border-radius: 8px;
			margin: 8px 0;
			border: 1px solid #e0e0e0;
			box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
			cursor: pointer;
			transition: transform 0.2s ease;
		}

		.user-message img:hover,
		.ai-message img:hover {
			transform: scale(1.02);
		}

		/* Mobile responsive adjustments */
		@media (max-width: 768px) {
			.floating-thumbnails {
				gap: 6px;
			}
			
			.floating-thumbnail {
				width: 50px;
				height: 50px;
			}

			.user-message img,
			.ai-message img {
				max-height: 200px;
			}

			.image-upload-icon {
				right: 10px;
			}
			#message-input {
				padding: 12px 36px 12px 16px;
			}
		}
	</style>
	<style>
		/* Styles for the API key setup message */
		#api-key-setup {
			display: none;
			background-color: #f8f9fa;
			border: 1px solid #ddd;
			border-radius: 8px;
			padding: 20px;
			margin: 20px auto;
			max-width: 800px;
			box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
		}

		#api-key-setup h2 {
			color: #333;
			margin-top: 0;
			border-bottom: 1px solid #eee;
			padding-bottom: 10px;
		}

		#api-key-setup code {
			background-color: #f1f1f1;
			padding: 2px 5px;
			border-radius: 3px;
			font-family: monospace;
		}

		/* API Key Form Styles */
		#api-key-form {
			background-color: #fff;
			border: 1px solid #ddd;
			border-radius: 8px;
			padding: 20px;
			margin-top: 20px;
		}

		#api-key-form h3 {
			margin-top: 0;
			color: #44CDF3;
		}

		#api-key-form .form-group {
			margin-bottom: 15px;
		}

		#api-key-form label {
			display: block;
			margin-bottom: 5px;
			font-weight: 500;
		}

		#api-key-form select,
		#api-key-form input {
			width: 100%;
			padding: 10px;
			border: 1px solid #ddd;
			border-radius: 4px;
			font-size: 14px;
		}

		#api-key-form .buttons {
			display: flex;
			justify-content: space-between;
			margin-top: 20px;
		}

		#api-key-form button {
			padding: 10px 15px;
			background-color: #44CDF3;
			color: white;
			border: none;
			border-radius: 4px;
			cursor: pointer;
			font-weight: bold;
		}

		#api-key-form button:hover {
			background-color: #2bb5db;
		}

		#reset-api-key {
			background-color: #f44336 !important;
		}

		#reset-api-key:hover {
			background-color: #d32f2f !important;
		}

		.api-key-status {
			margin-top: 10px;
			padding: 10px;
			border-radius: 4px;
			font-size: 14px;
		}

		.api-key-status.success {
			background-color: #e8f5e9;
			color: #2e7d32;
			border-left: 4px solid #4caf50;
		}

		.api-key-status.error {
			background-color: #ffebee;
			color: #c62828;
			border-left: 4px solid #f44336;
		}

		h1 a:hover {
			text-decoration: underline;
		}
	</style>
</head>

<body>
	<div id="chat-container">
		<div class="header">
			<div class="header-container">
				<div class="header-left">
					<a href="/" title="Go to Home Page">
						<img src="/logo.png" alt="Probe Logo" class="header-logo">
					</a>
					<div class="history-dropdown">
						<button id="history-button" class="history-button" title="Chat History">
							<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
								<path d="M12 1v6l4-4"></path>
								<path d="M21 12c0 5-4 9-9 9s-9-4-9-9 4-9 9-9c2.5 0 4.8 1 6.5 2.8"></path>
							</svg>
							History
						</button>
						<div id="history-dropdown-menu" class="history-dropdown-menu">
							<div class="history-dropdown-header">Recent Chats</div>
							<div id="history-loading" class="history-loading">Loading...</div>
							<div id="history-list" class="history-list"></div>
							<div id="history-empty" class="history-empty" style="display: none;">No recent chats</div>
						</div>
					</div>
					<a href="#" class="new-chat-link">New chat</a>
				</div>
				<div id="api-settings">
					<a href="#" id="header-reset-api-key"
						style="display: none; font-size: 12px; color: #f44336; text-decoration: none;">Reset API Key</a>
				</div>
			</div>
		</div>

		<div id="empty-state-logo" class="centered-logo-container">
			<h1><img src="/logo.png" alt="Probe Logo"><a href="https://probeai.dev/"
					style="color: inherit; text-decoration: none;">Probe </a>&nbsp;- AI-Native Code Understanding</h1>
		</div>

		<!-- API Key Setup Instructions -->
		<div id="api-key-setup">
			<h2>API Key Setup Required</h2>
			<p>To use the Probe AI chat interface, you need to configure at least one API key. You have two options:</p>

			<!-- API Key Web Form -->
			<div id="api-key-form">
				<h3>Option 1: Configure API Key in Browser</h3>
				<p>Enter your API key details below to start using the chat interface immediately:</p>

				<div class="form-group">
					<label for="api-provider">API Provider:</label>
					<select id="api-provider">
						<option value="anthropic">Anthropic Claude</option>
						<option value="openai">OpenAI</option>
						<option value="google">Google AI</option>
					</select>
				</div>

				<div class="form-group">
					<label for="api-key">API Key:</label>
					<input type="password" id="api-key" placeholder="Enter your API key">
				</div>

				<div class="form-group">
					<label for="api-url">Custom API URL (Optional):</label>
					<input type="text" id="api-url" placeholder="Leave blank for default API URL">
				</div>

				<div class="api-key-status" id="api-key-status" style="display: none;"></div>

				<div class="buttons">
					<button type="button" id="save-api-key">Save API Key</button>
				</div>

				<p style="margin-top: 10px; font-size: 0.9em; color: #666;">
					Your API key will be stored in your browser's local storage and sent with each request.
					No data is stored on our servers.
				</p>
			</div>

			<div style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #eee;">
				<h3>Option 2: Using Server-Side Configuration</h3>
				<p>Alternatively, you can configure API keys on the server:</p>

				<div style="background-color: #f8f9fa; padding: 15px; border-radius: 6px; margin-top: 10px;">
					<p><strong>Using a .env file:</strong></p>
					<ol style="margin-left: 20px;">
						<li>Create a <code>.env</code> file in the current directory by copying <code>.env.example</code></li>
						<li>Add your API key to the <code>.env</code> file (uncomment and replace with your key)</li>
						<li>Restart the application</li>
					</ol>

					<p style="margin-top: 15px;"><strong>Using environment variables:</strong></p>
					<ul style="margin-left: 20px;">
						<li>Anthropic: <code>ANTHROPIC_API_KEY=your_anthropic_api_key</code></li>
						<li>OpenAI: <code>OPENAI_API_KEY=your_openai_api_key</code></li>
						<li>Google AI: <code>GOOGLE_API_KEY=your_google_api_key</code></li>
					</ul>
				</div>
			</div>
		</div>
		<div id="messages" class="message-container"></div>
	</div>
	
	<form id="input-form" onsubmit="return false;">
		<div class="input-wrapper">
			<div class="textarea-container">
				<!-- Floating image thumbnails - positioned above textarea -->
				<div id="floating-thumbnails" class="floating-thumbnails" style="display: none;"></div>
				<textarea id="message-input" placeholder="Ask about code..." required rows="1"></textarea>
				<input type="file" id="image-upload" accept="image/*" multiple style="display: none;">
				<button type="button" id="image-upload-button" class="image-upload-icon" title="Upload images">
					<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
						<path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66L9.64 16.2a2 2 0 0 1-2.83-2.83l8.49-8.48"/>
					</svg>
				</button>
			</div>
			<button type="button" id="search-button">Search</button>
		</div>
	</form>
	<div class="search-suggestions">
		<ul>
			<li>Find functions that handle user authentication</li>
			<li>Search for database connection implementations</li>
			<li>Show error handling patterns in the codebase</li>
			<li>List all API endpoints in the project</li>
			<li>Find code that processes user input</li>
			<li>Show how configuration is loaded</li>
			<li>Find file parsing implementations</li>
		</ul>
		<div id="folder-info" class="folder-info"></div>
	</div>
	<div id="token-usage" class="token-usage">
		<div class="token-usage-content">
			<div class="token-usage-table">
				<div class="token-usage-row">
					<div class="token-label">Current:</div>
					<div class="token-value">
						<span id="current-request">0</span> req / <span id="current-response">0</span> resp
					</div>
				</div>
				<div class="token-usage-row">
					<div class="token-label">Cache:</div>
					<div class="token-value">
						<span id="current-cache-read">0</span> read / <span id="current-cache-write">0</span> write
					</div>
				</div>
				<div class="token-usage-row">
					<div class="token-label">Context:</div>
					<div class="token-value">
						<span id="context-window">0</span> tokens
					</div>
				</div>
				<div class="token-usage-row">
					<div class="token-label">Total Cache:</div>
					<div class="token-value">
						<span id="total-cache-read">0</span> read / <span id="total-cache-write">0</span> write
					</div>
				</div>
				<div class="token-usage-row">
					<div class="token-label">Total:</div>
					<div class="token-value">
						<span id="total-request">0</span> req / <span id="total-response">0</span> resp
					</div>
				</div>
			</div>
		</div>
	</div>
	<div class="footer">
		Powered by <a href="https://probeai.dev/" target="_blank">Probe</a>
	</div>
	</div>
	<script>
		// Token Usage Display Functionality
		// Function to update token usage display
		function updateTokenUsageDisplay(tokenUsage) {
			if (!tokenUsage) return;

			console.log('[TokenUsage] Updating display with:', tokenUsage);

			// Update current token usage
			if (tokenUsage.current) {
				document.getElementById('current-request').textContent = tokenUsage.current.request || 0;
				document.getElementById('current-response').textContent = tokenUsage.current.response || 0;

				// Update cache information in separate row
				const cacheRead = tokenUsage.current.cacheRead || 0;
				const cacheWrite = tokenUsage.current.cacheWrite || 0;
				document.getElementById('current-cache-read').textContent = cacheRead;
				document.getElementById('current-cache-write').textContent = cacheWrite;
			}

			// Update context window - force display even if 0
			const contextWindow = tokenUsage.contextWindow || 0;
			document.getElementById('context-window').textContent = contextWindow;

			// Update total cache information
			if (tokenUsage.total && tokenUsage.total.cache) {
				const totalCacheRead = tokenUsage.total.cache.read || 0;
				const totalCacheWrite = tokenUsage.total.cache.write || 0;
				document.getElementById('total-cache-read').textContent = totalCacheRead;
				document.getElementById('total-cache-write').textContent = totalCacheWrite;
			} else if (tokenUsage.total) {
				// Fallback to direct properties if cache object is not available
				const totalCacheRead = tokenUsage.total.cacheRead || 0;
				const totalCacheWrite = tokenUsage.total.cacheWrite || 0;
				document.getElementById('total-cache-read').textContent = totalCacheRead;
				document.getElementById('total-cache-write').textContent = totalCacheWrite;
			}

			// Update total token usage
			if (tokenUsage.total) {
				document.getElementById('total-request').textContent = tokenUsage.total.request || 0;
				document.getElementById('total-response').textContent = tokenUsage.total.response || 0;
			}

			// Show token usage display
			const tokenUsageElement = document.getElementById('token-usage');
			if (tokenUsageElement) {
				tokenUsageElement.style.display = 'block';
			}
		}

		// Make token usage functions available globally
		window.tokenUsageDisplay = {
			update: updateTokenUsageDisplay,
			fetch: function (sessionId) {
				if (!sessionId) {
					console.log('[TokenUsage] No session ID provided for fetchTokenUsage');
					// Try to get session ID from window object
					if (window.sessionId) {
						console.log(`[TokenUsage] Using session ID from window object: ${window.sessionId}`);
						sessionId = window.sessionId;
					} else {
						console.log('[TokenUsage] No session ID available, cannot fetch token usage');
						return;
					}
				}

				// Check if this session is still the current one
				if (sessionId !== window.sessionId) {
					console.log(`[TokenUsage] Session ID mismatch: ${sessionId} vs current ${window.sessionId}, skipping fetch`);
					return;
				}

				console.log(`[TokenUsage] Fetching token usage for session: ${sessionId}`);
				// Use a more reliable fetch with keepalive for Firefox
				fetch(`/api/token-usage?sessionId=${sessionId}`, {
					method: 'GET',
					cache: 'no-store',
					keepalive: true,
					headers: {
						'Cache-Control': 'no-cache',
						'Pragma': 'no-cache'
					}
				})
					.then(response => {
						console.log(`[TokenUsage] Response status: ${response.status}`);

						if (response.ok) {
							return response.json();
						}
						throw new Error('Failed to fetch token usage');
					})
					.then(data => {
						console.log('[TokenUsage] Received token usage data:', data);
						updateTokenUsageDisplay(data);
					})
					.catch(error => {
						console.error('[TokenUsage] Error fetching token usage:', error);
						// Display a small error indicator in the token usage display
						const tokenUsageElement = document.getElementById('token-usage');
						if (tokenUsageElement && tokenUsageElement.style.display !== 'none') {
							const errorIndicator = document.createElement('div');
							errorIndicator.style.color = '#f44336';
							errorIndicator.style.fontSize = '10px';
							errorIndicator.style.marginTop = '5px';
							errorIndicator.textContent = 'Error updating token usage';

							// Remove any existing error indicators
							const existingIndicators = tokenUsageElement.querySelectorAll('[data-error-indicator]');
							existingIndicators.forEach(el => el.remove());

							// Add the data attribute for future reference
							errorIndicator.setAttribute('data-error-indicator', 'true');

							// Add to the token usage display
							tokenUsageElement.querySelector('.token-usage-content').appendChild(errorIndicator);

							// Remove after 5 seconds
							setTimeout(() => {
								if (errorIndicator.parentNode) {
									errorIndicator.parentNode.removeChild(errorIndicator);
								}
							}, 5000);
						}
					});
			}
		};

		function convertSvgToPng(svgElement, containerDiv, index) {
			if (!svgElement) {
				console.error('No SVG found!');
				return;
			}

			try {
				// Get the actual rendered size of the SVG
				const rect = svgElement.getBoundingClientRect();
				const svgWidth = rect.width;
				const svgHeight = rect.height;
				console.log(`SVG rendered size: ${svgWidth}x${svgHeight}`);

				// Define scale factor for higher resolution (increase for more clarity)
				const scale = 6; // Try 3 or 4 if still blurry

				// Create canvas with scaled dimensions
				const canvasWidth = svgWidth * scale;
				const canvasHeight = svgHeight * scale;
				const canvas = document.createElement('canvas');
				canvas.width = canvasWidth;
				canvas.height = canvasHeight;
				const ctx = canvas.getContext('2d');

				// Enable image smoothing for better quality
				ctx.imageSmoothingEnabled = true;
				ctx.imageSmoothingQuality = 'high';

				// Serialize SVG to string
				const svgString = new XMLSerializer().serializeToString(svgElement);
				const svgDataUrl = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svgString);

				const img = new Image();
				img.onload = function () {
					// Draw the image onto the canvas at scaled size
					ctx.drawImage(img, 0, 0, canvasWidth, canvasHeight);

					// Convert canvas to PNG data URL
					const pngDataUrl = canvas.toDataURL('image/png');

					// Create the PNG image element
					const pngImage = document.createElement('img');
					pngImage.src = pngDataUrl;
					pngImage.width = svgWidth; // Display at original size
					pngImage.height = svgHeight;
					pngImage.alt = 'Diagram as PNG';
					pngImage.className = 'mermaid-png';
					pngImage.setAttribute('data-full-size', pngDataUrl); // Store full-size image URL for zoom

					// Log PNG natural size to verify resolution
					pngImage.onload = function () {
						console.log(`PNG natural size: ${this.naturalWidth}x${this.naturalHeight}`);
					};

					// Create a container for the image with zoom functionality
					const container = document.createElement('div');
					container.className = 'mermaid-container';

					// Create zoom icon
					const zoomIcon = document.createElement('div');
					zoomIcon.className = 'zoom-icon';
					zoomIcon.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="11" y1="8" x2="11" y2="14"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>';

					// Add click event to zoom icon
					zoomIcon.addEventListener('click', function (e) {
						e.stopPropagation();
						showDiagramDialog(pngDataUrl);
					});

					// Replace the SVG with the PNG image in the container
					svgElement.style.display = 'none';
					container.appendChild(pngImage);
					container.appendChild(zoomIcon);
					svgElement.insertAdjacentElement('afterend', container);

					console.log(`Replaced SVG with PNG image (index: ${index || 0})`);
				};
				img.onerror = function () {
					console.error('Error loading SVG image for conversion');
				};
				img.src = svgDataUrl;
			} catch (error) {
				console.error('Error in SVG to PNG conversion process:', error);
			}
		}

		// Function to show diagram in fullscreen dialog
		function showDiagramDialog(imageUrl) {
			// Create dialog if it doesn't exist
			let dialog = document.getElementById('diagram-dialog');
			if (!dialog) {
				dialog = document.createElement('div');
				dialog.id = 'diagram-dialog';
				dialog.className = 'diagram-dialog';

				const dialogContent = document.createElement('div');
				dialogContent.className = 'diagram-dialog-content';

				const closeButton = document.createElement('div');
				closeButton.className = 'close-dialog';
				closeButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>';
				closeButton.addEventListener('click', function () {
					dialog.classList.remove('active');
				});

				dialog.appendChild(dialogContent);
				dialog.appendChild(closeButton);
				document.body.appendChild(dialog);

				// Close dialog when clicking outside content
				dialog.addEventListener('click', function (e) {
					if (e.target === dialog) {
						dialog.classList.remove('active');
					}
				});

				// Close dialog with Escape key
				document.addEventListener('keydown', function (e) {
					if (e.key === 'Escape' && dialog.classList.contains('active')) {
						dialog.classList.remove('active');
					}
				});
			}

			// Update dialog content with the image
			const dialogContent = dialog.querySelector('.diagram-dialog-content');
			dialogContent.innerHTML = '';

			const img = document.createElement('img');
			img.src = imageUrl;
			img.alt = 'Diagram (Full Size)';

			// Ensure image fits screen by checking dimensions after loading
			img.onload = function () {
				// Image is now loaded, ensure it fits within the dialog content
				const viewportWidth = window.innerWidth * 0.9 - 40; // 90% of viewport minus padding
				const viewportHeight = window.innerHeight * 0.9 - 40; // 90% of viewport minus padding

				console.log(`Image natural size: ${img.naturalWidth}x${img.naturalHeight}`);
				console.log(`Available viewport space: ${viewportWidth}x${viewportHeight}`);

				// Image will be constrained by CSS max-width/max-height and object-fit
			};

			dialogContent.appendChild(img);

			// Show dialog
			dialog.classList.add('active');
		}
		// Initialize session ID - either from URL or generate new one
		let sessionId;
		
		// Check if session ID is provided via URL (from server-side injection)
		const sessionIdFromUrl = document.body.getAttribute('data-session-id');
		if (sessionIdFromUrl) {
			sessionId = sessionIdFromUrl;
			console.log(`Using session ID from URL: ${sessionId}`);
			// Restore session history for existing sessions
			restoreSessionHistory(sessionId);
		} else {
			// Generate new session ID for root path visits
			sessionId = crypto.randomUUID();
			console.log(`Generated new session ID: ${sessionId}`);
		}

		// Make session ID available to other scripts
		// We use both direct property assignment and event dispatch for compatibility
		// Direct property is used by internal functions like tokenUsageDisplay.fetch
		window.sessionId = sessionId;

		// Dispatch an event with the session ID for any external scripts that may be listening
		window.dispatchEvent(new MessageEvent('message', {
			data: { sessionId: sessionId }
		}));

		// Helper function to extract content from XML-wrapped messages
		function extractContentFromXML(content) {
			// Handle different XML patterns used by the assistant
			const patterns = [
				/<task>([\s\S]*?)<\/task>/,
				/<attempt_completion>\s*<result>([\s\S]*?)<\/result>\s*<\/attempt_completion>/,
				/<result>([\s\S]*?)<\/result>/
			];
			
			for (const pattern of patterns) {
				const match = content.match(pattern);
				if (match) {
					return match[1].trim();
				}
			}
			
			// Remove all internal reasoning and tool call XML tags
			let cleanContent = content;
			
			// Remove thinking tags (internal reasoning) - these are never shown to users
			cleanContent = cleanContent.replace(/<thinking>[\s\S]*?<\/thinking>/gs, '');
			
			// Remove all tool calls - these are rendered separately as tool call boxes
			cleanContent = cleanContent.replace(/<search>\s*<query>.*?<\/query>\s*(?:<path>.*?<\/path>)?\s*(?:<allow_tests>.*?<\/allow_tests>)?\s*<\/search>/gs, '');
			cleanContent = cleanContent.replace(/<extract>\s*<file_path>.*?<\/file_path>\s*(?:<line>.*?<\/line>)?\s*(?:<end_line>.*?<\/end_line>)?\s*<\/extract>/gs, '');
			cleanContent = cleanContent.replace(/<query>\s*<pattern>.*?<\/pattern>\s*(?:<path>.*?<\/path>)?\s*(?:<language>.*?<\/language>)?\s*<\/query>/gs, '');
			cleanContent = cleanContent.replace(/<listFiles>\s*<directory>.*?<\/directory>\s*(?:<pattern>.*?<\/pattern>)?\s*<\/listFiles>/gs, '');
			cleanContent = cleanContent.replace(/<searchFiles>\s*<pattern>.*?<\/pattern>\s*(?:<directory>.*?<\/directory>)?\s*<\/searchFiles>/gs, '');
			
			// Clean up extra whitespace and empty lines
			cleanContent = cleanContent.replace(/\n\s*\n\s*\n/g, '\n\n').replace(/^\s+|\s+$/g, '');
			
			// If after cleaning there's no meaningful content, return empty string
			if (!cleanContent || cleanContent.trim().length < 3) {
				return '';
			}
			
			return cleanContent;
		}

		// Function to add a user message to the chat display
		function addUserMessage(content, images = []) {
			const userMsgDiv = document.createElement('div');
			userMsgDiv.className = 'user-message markdown-content';
			
			// Extract content from XML if wrapped
			const cleanContent = extractContentFromXML(content);
			
			// Render the text message
			userMsgDiv.innerHTML = renderMarkdown(cleanContent);
			
			// Handle images if present
			if (images && images.length > 0) {
				images.forEach(imageData => {
					const img = document.createElement('img');
					img.src = imageData.url || imageData;
					img.style.maxWidth = '100%';
					img.style.marginTop = '10px';
					userMsgDiv.appendChild(img);
				});
			}
			
			messagesDiv.appendChild(userMsgDiv);
			
			// Apply syntax highlighting to code blocks
			userMsgDiv.querySelectorAll('pre code').forEach((block) => {
				hljs.highlightElement(block);
			});
		}

		// Function to parse and extract tool calls from assistant message content
		function parseToolCallsFromContent(content) {
			const toolCalls = [];
			
			// Pattern to match actual tool call formats that are sent via SSE
			// These are the tool calls that users see in real-time, not internal reasoning
			const toolPatterns = [
				{ name: 'search', pattern: /<search>\s*<query>(.*?)<\/query>\s*(?:<path>(.*?)<\/path>)?\s*(?:<allow_tests>(.*?)<\/allow_tests>)?\s*<\/search>/s },
				{ name: 'extract', pattern: /<extract>\s*<file_path>(.*?)<\/file_path>\s*(?:<line>(.*?)<\/line>)?\s*(?:<end_line>(.*?)<\/end_line>)?\s*<\/extract>/s },
				{ name: 'query', pattern: /<query>\s*<pattern>(.*?)<\/pattern>\s*(?:<path>(.*?)<\/path>)?\s*(?:<language>(.*?)<\/language>)?\s*<\/query>/s },
				{ name: 'listFiles', pattern: /<listFiles>\s*<directory>(.*?)<\/directory>\s*(?:<pattern>(.*?)<\/pattern>)?\s*<\/listFiles>/s },
				{ name: 'searchFiles', pattern: /<searchFiles>\s*<pattern>(.*?)<\/pattern>\s*(?:<directory>(.*?)<\/directory>)?\s*<\/searchFiles>/s },
			];
			
			toolPatterns.forEach(({ name, pattern }) => {
				const matches = content.matchAll(new RegExp(pattern.source, pattern.flags + 'g'));
				for (const match of matches) {
					const toolCall = {
						name: name,
						timestamp: new Date().toISOString(),
						status: 'completed',
						args: {}
					};
					
					// Map captured groups to appropriate argument names
					if (name === 'search') {
						toolCall.args.query = match[1]?.trim() || '';
						toolCall.args.path = match[2]?.trim() || '.';
						toolCall.args.allow_tests = match[3]?.trim() === 'true';
					} else if (name === 'extract') {
						toolCall.args.file_path = match[1]?.trim() || '';
						toolCall.args.line = match[2] ? parseInt(match[2].trim()) : undefined;
						toolCall.args.end_line = match[3] ? parseInt(match[3].trim()) : undefined;
					} else if (name === 'query') {
						toolCall.args.pattern = match[1]?.trim() || '';
						toolCall.args.path = match[2]?.trim() || '.';
						toolCall.args.language = match[3]?.trim() || '';
					} else if (name === 'listFiles') {
						toolCall.args.directory = match[1]?.trim() || '.';
						toolCall.args.pattern = match[2]?.trim() || '';
					} else if (name === 'searchFiles') {
						toolCall.args.pattern = match[1]?.trim() || '';
						toolCall.args.directory = match[2]?.trim() || '.';
					}
					
					toolCalls.push(toolCall);
				}
			});
			
			return toolCalls;
		}

		// Function to add an assistant message to the chat display
		function addAssistantMessage(content) {
			const aiMsgDiv = document.createElement('div');
			aiMsgDiv.className = 'ai-message markdown-content';
			
			// Parse tool calls from the content first
			const toolCalls = parseToolCallsFromContent(content);
			
			// Add tool calls to the message if any exist
			toolCalls.forEach(toolCall => {
				addToolCallToMessage(aiMsgDiv, toolCall);
			});
			
			// Extract final result content (skip tool call XML tags)
			const cleanContent = extractContentFromXML(content);
			
			// Only add text content if there's actual result content
			if (cleanContent && cleanContent.trim()) {
				// Store the original message for copying
				aiMsgDiv.setAttribute('data-original-markdown', cleanContent);
				
				// Process and render the content
				const processedContent = processMessageForDisplay(cleanContent);
				const contentDiv = document.createElement('div');
				contentDiv.innerHTML = renderMarkdown(processedContent);
				aiMsgDiv.appendChild(contentDiv);
				
				// Apply syntax highlighting to code blocks
				contentDiv.querySelectorAll('pre code').forEach((block) => {
					hljs.highlightElement(block);
				});
				
				// Apply Mermaid rendering to diagrams
				const mermaidElements = contentDiv.querySelectorAll('.mermaid, .language-mermaid');
				if (mermaidElements.length > 0) {
					console.log(`Found ${mermaidElements.length} mermaid diagrams in restored message`);
					try {
						if (typeof mermaid.run === 'function') {
							mermaid.run({ nodes: mermaidElements });
						} else if (typeof mermaid.init === 'function') {
							mermaid.init(undefined, mermaidElements);
						}
					} catch (error) {
						console.error('Error rendering mermaid in restored message:', error);
					}
				}
			}
			
			// Add to messages container
			messagesDiv.appendChild(aiMsgDiv);
		}

		// Function to restore session history from server
		async function restoreSessionHistory(sessionId) {
			try {
				console.log(`Restoring session history for: ${sessionId}`);
				const response = await fetch(`/api/session/${sessionId}/history`);
				const data = await response.json();
				
				console.log(`[DEBUG] Session restoration data:`, {
					exists: data.exists,
					historyLength: data.history ? data.history.length : 'null/undefined',
					condition: data.exists && data.history && data.history.length > 0
				});
				
				if (data.exists && data.history && data.history.length > 0) {
					console.log(`Restored ${data.history.length} messages for session: ${sessionId}`);
					
					// Count message types for debugging
					const messageTypes = {};
					data.history.forEach(msg => {
						messageTypes[msg.role] = (messageTypes[msg.role] || 0) + 1;
					});
					console.log(`[DEBUG] Message types to restore:`, messageTypes);
					
					// Render restored messages
					let currentAiMessage = null;
					data.history.forEach((message, index) => {
						console.log(`[DEBUG] Processing message ${index + 1}/${data.history.length}: role=${message.role}`);
						if (message.role === 'user') {
							// Ensure images is always an array
							const images = Array.isArray(message.images) ? message.images : [];
							addUserMessage(message.content, images);
							currentAiMessage = null; // Reset for new conversation turn
						} else if (message.role === 'assistant') {
							addAssistantMessage(message.content);
							// Get the most recent AI message for tool call rendering
							const messagesDiv = document.getElementById('messages');
							const aiMessages = messagesDiv.querySelectorAll('.ai-message');
							currentAiMessage = aiMessages[aiMessages.length - 1];
						} else if (message.role === 'toolCall') {
							console.log(`[DEBUG] Rendering toolCall message`);
							// Handle tool call messages during restoration
							try {
								// Parse the tool call from the stored message
								const toolCall = {
									name: message.metadata?.name || 'unknown',
									args: message.metadata?.args || {},
									timestamp: message.timestamp,
									status: 'completed'
								};
								
								// If we have a current AI message, add the tool call to it
								if (currentAiMessage) {
									addToolCallToMessage(currentAiMessage, toolCall);
								} else {
									console.log(`[DEBUG] No current AI message for tool call, creating temporary message`);
									// Create a temporary AI message for the tool call
									const tempDiv = document.createElement('div');
									tempDiv.className = 'ai-message';
									const messagesDiv = document.getElementById('messages');
									messagesDiv.appendChild(tempDiv);
									addToolCallToMessage(tempDiv, toolCall);
									currentAiMessage = tempDiv;
								}
							} catch (error) {
								console.error('[DEBUG] Error rendering tool call:', error, message);
							}
						} else {
							console.log(`[DEBUG] Skipping message with role: ${message.role}`);
						}
					});
					
					// Update token usage if available
					if (data.tokenUsage && window.tokenUsageDisplay) {
						window.tokenUsageDisplay.update(data.tokenUsage);
					}
					
					// Update UI to reflect restored chat state
					positionInputForm();
					
					// Hide search suggestions when loading from history
					const searchSuggestions = document.querySelector('.search-suggestions');
					if (searchSuggestions) {
						searchSuggestions.style.display = 'none';
					}
					
					// Ensure all Mermaid diagrams are rendered after restoration
					setTimeout(() => {
						const allMermaidElements = document.querySelectorAll('.mermaid:not([data-processed]), .language-mermaid:not([data-processed])');
						if (allMermaidElements.length > 0) {
							console.log(`Rendering ${allMermaidElements.length} unprocessed mermaid diagrams after session restoration`);
							try {
								if (typeof mermaid.run === 'function') {
									mermaid.run({ nodes: allMermaidElements });
								} else if (typeof mermaid.init === 'function') {
									mermaid.init(undefined, allMermaidElements);
								}
							} catch (error) {
								console.error('Error rendering mermaid after session restoration:', error);
							}
						}
					}, 100); // Small delay to ensure DOM is fully updated
				} else {
					console.log(`[DEBUG] No history found for session: ${sessionId}`, {
						exists: data.exists,
						historyExists: !!data.history,
						historyLength: data.history ? data.history.length : 'N/A'
					});
					// Show user-friendly message for session not found
					showSessionNotFoundMessage(sessionId);
				}
			} catch (error) {
				console.error('[DEBUG] Error restoring session history:', error);
				console.error('[DEBUG] Error stack:', error.stack);
				// Show error message for network or other errors
				showSessionNotFoundMessage(sessionId);
			}
		}

		// Function to show session not found message
		function showSessionNotFoundMessage(sessionId) {
			const messageDiv = document.createElement('div');
			messageDiv.className = 'ai-message markdown-content';
			messageDiv.style.borderLeft = '4px solid #ff6b6b';
			messageDiv.style.backgroundColor = '#fff5f5';
			messageDiv.innerHTML = `
				<div style="padding: 15px;">
					<h3 style="margin-top: 0; color: #c92a2a;">Session Not Found</h3>
					<p>The chat session with ID <code>${sessionId}</code> was not found or has expired.</p>
					<p>This could happen if:</p>
					<ul>
						<li>The session has been inactive for more than 2 hours</li>
						<li>The server was restarted</li>
						<li>The session ID is invalid</li>
					</ul>
					<p>You can start a new conversation by <a href="/" style="color: #1976d2;">returning to the home page</a>.</p>
				</div>
			`;
			messagesDiv.appendChild(messageDiv);
			
			// Update UI to show the message
			positionInputForm();
		}

		// Function to update URL when session changes (for new chats)
		function updateUrlForSession(sessionId) {
			const newUrl = `/chat/${sessionId}`;
			if (window.location.pathname !== newUrl) {
				window.history.pushState({ sessionId }, '', newUrl);
				console.log(`Updated URL to: ${newUrl}`);
			}
		}

		// Handle browser back/forward navigation
		window.addEventListener('popstate', (event) => {
			if (event.state && event.state.sessionId) {
				// User navigated to a different session
				console.log(`Navigating to session: ${event.state.sessionId}`);
				window.location.reload(); // Reload to restore the session
			}
		});

		// History dropdown functionality
		class HistoryDropdown {
			constructor() {
				this.button = document.getElementById('history-button');
				this.menu = document.getElementById('history-dropdown-menu');
				this.loading = document.getElementById('history-loading');
				this.list = document.getElementById('history-list');
				this.empty = document.getElementById('history-empty');
				this.isOpen = false;
				
				this.init();
			}

			init() {
				// Button click handler
				this.button.addEventListener('click', (e) => {
					e.preventDefault();
					e.stopPropagation();
					this.toggle();
				});

				// Close dropdown when clicking outside
				document.addEventListener('click', (e) => {
					if (!this.menu.contains(e.target) && !this.button.contains(e.target)) {
						this.close();
					}
				});

				// Prevent dropdown from closing when clicking inside
				this.menu.addEventListener('click', (e) => {
					e.stopPropagation();
				});
			}

			async toggle() {
				if (this.isOpen) {
					this.close();
				} else {
					await this.open();
				}
			}

			async open() {
				this.isOpen = true;
				this.menu.classList.add('show');
				this.showLoading();
				
				try {
					await this.loadSessions();
				} catch (error) {
					console.error('Error loading sessions:', error);
					this.showError();
				}
			}

			close() {
				this.isOpen = false;
				this.menu.classList.remove('show');
			}

			showLoading() {
				this.loading.style.display = 'block';
				this.list.style.display = 'none';
				this.empty.style.display = 'none';
			}

			showList() {
				this.loading.style.display = 'none';
				this.list.style.display = 'block';
				this.empty.style.display = 'none';
			}

			showEmpty() {
				this.loading.style.display = 'none';
				this.list.style.display = 'none';
				this.empty.style.display = 'block';
			}

			showError() {
				this.loading.textContent = 'Error loading history';
				this.loading.style.color = '#f44336';
			}

			async loadSessions() {
				try {
					const response = await fetch('/api/sessions');
					const data = await response.json();
					
					if (data.sessions && data.sessions.length > 0) {
						this.renderSessions(data.sessions);
						this.showList();
					} else {
						this.showEmpty();
					}
				} catch (error) {
					console.error('Error fetching sessions:', error);
					throw error;
				}
			}

			renderSessions(sessions) {
				this.list.innerHTML = '';
				
				sessions.forEach(session => {
					const item = document.createElement('div');
					item.className = 'history-item';
					item.dataset.sessionId = session.sessionId;
					
					// Check if this is the current session
					const isCurrent = session.sessionId === window.sessionId;
					if (isCurrent) {
						item.style.backgroundColor = '#e3f2fd';
					}
					
					item.innerHTML = `
						<div class="history-item-preview">${this.escapeHtml(session.preview)}</div>
						<div class="history-item-meta">
							<span class="history-item-time">${session.relativeTime}</span>
							<span class="history-item-count">${session.messageCount} messages</span>
						</div>
					`;

					item.addEventListener('click', () => {
						if (!isCurrent) {
							this.navigateToSession(session.sessionId);
						}
						this.close();
					});

					this.list.appendChild(item);
				});
			}

			navigateToSession(sessionId) {
				const url = `/chat/${sessionId}`;
				console.log(`Navigating to session: ${sessionId}`);
				window.location.href = url;
			}

			escapeHtml(text) {
				const div = document.createElement('div');
				div.textContent = text;
				return div.innerHTML;
			}
		}

		// Initialize history dropdown
		document.addEventListener('DOMContentLoaded', () => {
			new HistoryDropdown();
		});
		const messagesDiv = document.getElementById('messages');
		const form = document.getElementById('input-form');
		const searchSuggestionsDiv = document.querySelector('.search-suggestions');
		const input = document.getElementById('message-input');
		const folderListDiv = document.getElementById('folder-list');

		// Position the input form in the center initially and handle UI elements visibility
		function positionInputForm() {
			const footer = document.querySelector('.footer');
			const header = document.querySelector('.header');
			const emptyStateLogo = document.getElementById('empty-state-logo');

			if (messagesDiv.children.length === 0) {
				form.classList.add('centered');
				form.classList.remove('bottom');
				// Show footer when no messages
				if (footer) {
					footer.style.display = 'block';
				}
				// Always show the header (it contains the history dropdown)
				if (header) {
					header.style.display = 'block';
				}
				if (emptyStateLogo) {
					emptyStateLogo.style.display = 'block';
				}
			} else {
				form.classList.remove('centered');
				form.classList.add('bottom');
				// Hide footer when chat is started
				if (footer) {
					footer.style.display = 'none';
				}
				// Show the top header and hide the centered logo
				if (header) {
					header.style.display = 'block';
				}
				if (emptyStateLogo) {
					emptyStateLogo.style.display = 'none';
				}
			}
		}

		// Make search suggestions clickable
		function setupSearchSuggestions() {
			document.querySelectorAll('.search-suggestions li').forEach(item => {
				item.addEventListener('click', () => {
					input.value = item.textContent;
					input.focus();
				});
			});
		}

		// Initialize on page load
		window.addEventListener('load', () => {
			setupSearchSuggestions();
			positionInputForm();
			positionSearchSuggestions();

			// Focus the input field on page load
			setTimeout(() => {
				const inputField = document.getElementById('message-input');
				if (inputField) {
					inputField.focus();
				}
			}, 100);
		});


		// Position search suggestions relative to input form
		function positionSearchSuggestions() {
			const formRect = form.getBoundingClientRect();

			if (form.classList.contains('centered')) {
				// Position directly below the form
				searchSuggestionsDiv.style.top = formRect.bottom + 'px';
				searchSuggestionsDiv.style.display = 'block';
			} else {
				searchSuggestionsDiv.style.display = 'none';
			}
		}

		// Update search suggestions position when window is resized
		window.addEventListener('resize', positionSearchSuggestions);

		// Check if Mermaid is properly loaded
		function checkMermaidLoaded() {
			if (typeof mermaid === 'undefined') {
				console.error('Mermaid is not loaded properly');
				return false;
			}
			console.log('Mermaid version:', mermaid.version);
			return true;
		}

		// Initialize mermaid
		if (checkMermaidLoaded()) {
			mermaid.initialize({
				startOnLoad: false,
				theme: 'default',
				securityLevel: 'loose',
				flowchart: { htmlLabels: true },
				logLevel: 3, // Add logging for debugging (1: error, 2: warn, 3: info, 4: debug, 5: trace)
				fontFamily: 'monospace'
			});

			// Run mermaid on page load to render the test diagram
			window.addEventListener('DOMContentLoaded', () => {
				setTimeout(() => {
					try {
						console.log('Running mermaid on page load');
						mermaid.run();
					} catch (error) {
						console.error('Error initializing mermaid:', error);
					}
				}, 500);
			});
		}

		// Configure marked.js
		// Configure Marked.js with logging
		marked.setOptions({
			highlight: function (code, lang) {
				console.log(`Highlighting code with language: ${lang}`);
				if (lang === 'mermaid') {
					console.log('Returning mermaid div');
					return `<div class="mermaid">${code}</div>`;
				}
				const language = hljs.getLanguage(lang) ? lang : 'plaintext';
				return hljs.highlight(code, { language }).value;
			},
			langPrefix: 'hljs language-',
			gfm: true,
			breaks: true
		});
		// Fetch API key status and check for no API keys mode on page load
		window.addEventListener('DOMContentLoaded', async () => {
			// First check if we have an API key in local storage
			const storedApiKey = localStorage.getItem('probeApiKey');
			if (storedApiKey) {
				// Show the reset button in the header
				const headerResetButton = document.getElementById('header-reset-api-key');
				if (headerResetButton) {
					headerResetButton.style.display = 'inline-block';
				}
			}
			// Check if we're in API key setup mode
			const apiKeySetupDiv = document.getElementById('api-key-setup');
			const inputForm = document.getElementById('input-form');
			const searchSuggestions = document.querySelector('.search-suggestions');

			// If API key setup is visible, we're in API setup mode
			if (apiKeySetupDiv && window.getComputedStyle(apiKeySetupDiv).display !== 'none') {
				// Add class to body for API setup mode styling
				document.body.classList.add('api-setup-mode');

				// Hide search suggestions and input form
				if (inputForm) inputForm.style.display = 'none';
				if (searchSuggestions) searchSuggestions.style.display = 'none';
			} else {
				// Remove API setup mode class if not in setup mode
				document.body.classList.remove('api-setup-mode');
			}

			try {
				const response = await fetch('/folders');
				const data = await response.json();

				// Check if we're in no API keys mode
				if (data.noApiKeysMode) {
					handleNoApiKeysMode();
				}

				// Display folder information
				displayFolderInfo(data.folders);
			} catch (error) {
				console.error('Error fetching API status:', error);
			}
		});

		// Function to display folder information
		function displayFolderInfo(folders) {
			const folderInfoDiv = document.getElementById('folder-info');

			if (!folderInfoDiv) return;

			// Clear any existing content
			folderInfoDiv.innerHTML = '';

			// Set a loading message
			folderInfoDiv.textContent = 'Determining search location...';

			// Fetch the current directory from the server's /folders endpoint
			fetch('/folders')
				.then(response => response.json())
				.then(data => {
					// Use the currentDir property which contains the absolute path
					if (data.currentDir) {
						// Display the absolute path from the server
						folderInfoDiv.textContent = `Searching in: ${data.currentDir}`;

						// If there are multiple folders, show that info
						if (data.folders && data.folders.length > 1) {
							folderInfoDiv.textContent += ` (and ${data.folders.length - 1} other folder${data.folders.length > 2 ? 's' : ''})`;
						}
					}
					// Fallback to folders if currentDir is not available
					else if (data.folders && data.folders.length > 0) {
						folderInfoDiv.textContent = `Searching in: ${data.folders[0]}`;

						if (data.folders.length > 1) {
							folderInfoDiv.textContent += ` (and ${data.folders.length - 1} other folder${data.folders.length > 2 ? 's' : ''})`;
						}
					}
					// Last resort fallback
					else {
						folderInfoDiv.textContent = `Searching in: . (current directory)`;
					}
				})
				.catch(error => {
					console.error('Error fetching folder info:', error);
					folderInfoDiv.textContent = `Searching in: . (current directory)`;
				});
		}

		// Handle no API keys mode
		function handleNoApiKeysMode() {
			// Check if body has the data-no-api-keys attribute
			const noApiKeys = document.body.getAttribute('data-no-api-keys') === 'true';

			// Check if API key is already stored in local storage
			const storedApiKey = localStorage.getItem('probeApiKey');

			// Add or remove api-setup-mode class based on whether we need to show the API key setup
			if (noApiKeys && !storedApiKey) {
				document.body.classList.add('api-setup-mode');
			} else {
				document.body.classList.remove('api-setup-mode');
			}

			// Get UI elements
			const apiKeySetupDiv = document.getElementById('api-key-setup');
			const inputForm = document.getElementById('input-form');
			const searchSuggestions = document.querySelector('.search-suggestions');

			if (noApiKeys && !storedApiKey) {
				console.log('No API keys detected and no local storage key - showing setup instructions');

				// Show the API key setup div
				if (apiKeySetupDiv) {
					apiKeySetupDiv.style.display = 'block';
				}

				// Hide the chat interface elements
				if (inputForm) {
					inputForm.style.display = 'none';
				}

				if (searchSuggestions) {
					searchSuggestions.style.display = 'none';
				}
			} else if (noApiKeys && storedApiKey) {
				console.log('No server API keys but local storage key found - enabling chat interface');

				// Hide the API key setup div
				if (apiKeySetupDiv) {
					apiKeySetupDiv.style.display = 'none';
				}

				// Show the chat interface elements
				if (inputForm) {
					inputForm.style.display = 'flex';
				}

				// Remove API setup mode class
				document.body.classList.remove('api-setup-mode');
			}
		}


		// Render markdown content
		function renderMarkdown(text) {
			// Just parse the markdown and return the HTML
			return marked.parse(text);
		}

		// Test function to manually render a Mermaid diagram
		function testMermaidRendering() {
			console.log('Testing Mermaid rendering...');
			try {
				// Create a simple test diagram directly
				const testDiv = document.createElement('div');
				testDiv.className = 'mermaid';
				testDiv.textContent = 'graph TD;\nA-->B;';
				document.body.appendChild(testDiv);

				console.log('Created test diagram with content:', testDiv.textContent);

				// Render the direct mermaid div
				setTimeout(() => {
					try {
						console.log('Running mermaid on test div');
						if (typeof mermaid.run === 'function') {
							console.log('Using mermaid.run() for test');
							mermaid.run({
								nodes: [testDiv]
							});
						} else if (typeof mermaid.init === 'function') {
							console.log('Using mermaid.init() for test');
							mermaid.init(undefined, [testDiv]);
						}

						// Verify if rendering worked
						setTimeout(() => {
							const svg = testDiv.querySelector('svg');
							if (svg) {
								console.log('Test diagram rendered successfully!');
							} else {
								console.error('Test diagram did not render to SVG');
							}

							// Remove test div after verification
							document.body.removeChild(testDiv);
						}, 100);
					} catch (error) {
						console.error('Error rendering test mermaid diagram:', error);
						console.error('Error details:', error.message);

						// Remove test div on error
						document.body.removeChild(testDiv);
					}
				}, 200);
			} catch (error) {
				console.error('Unexpected error in test function:', error);
			}
		}

		// Run test on page load
		window.addEventListener('DOMContentLoaded', () => {
			setTimeout(testMermaidRendering, 1000);
		});

		// Connect to SSE endpoint for tool calls
		let eventSource;
		let currentAiMessageDiv = null;

		function connectToToolEvents() {
			// Close existing connection if any
			if (eventSource) {
				console.log('Closing existing SSE connection');
				eventSource.close();
			}

			// Clear any existing displayed tool calls when connecting with a new session ID
			if (window.displayedToolCalls) {
				window.displayedToolCalls.clear();
				console.log('Cleared displayed tool calls for new session');
			}

			console.log(`%c Connecting to SSE endpoint with session ID: ${sessionId}`, 'background: #FF9800; color: white; padding: 2px 5px; border-radius: 2px;');
			// Connect to SSE endpoint with session ID
			const sseUrl = `/api/tool-events?sessionId=${sessionId}`;
			console.log('SSE URL:', sseUrl);

			// Add a timestamp to prevent caching in Firefox
			const nocacheUrl = `${sseUrl}&_nocache=${Date.now()}`;
			eventSource = new EventSource(nocacheUrl);

			// Handle connection event
			eventSource.addEventListener('connection', (event) => {
				console.log('%c Connected to tool events stream', 'background: #4CAF50; color: white; padding: 2px 5px; border-radius: 2px;', event.data);
				try {
					const connectionData = JSON.parse(event.data);
					console.log('Connection data:', connectionData);
				} catch (error) {
					console.error('Error parsing connection data:', error, event.data);
				}
			});

			// Handle test events
			eventSource.addEventListener('test', (event) => {
				console.log('%c Received test event:', 'background: #9C27B0; color: white; padding: 2px 5px; border-radius: 2px;', event.data);
				try {
					const testData = JSON.parse(event.data);
					console.log('%c Test data:', 'background: #673AB7; color: white; padding: 2px 5px; border-radius: 2px;', testData);

					// Log specific test data properties
					console.log('Test message:', testData.message);
					console.log('Test timestamp:', testData.timestamp);
					console.log('Test session ID:', testData.sessionId);

					if (testData.status) {
						console.log('Test status:', testData.status);
					}

					if (testData.connectionInfo) {
						console.log('Connection info:', testData.connectionInfo);
					}

					if (testData.sequence === 2) {
						console.log('%c SSE connection fully verified with follow-up test', 'background: #4CAF50; color: white; padding: 2px 5px; border-radius: 2px;');
					}

					// Add a visual indicator that the SSE connection is working
					const connectionIndicator = document.createElement('div');
					connectionIndicator.style.position = 'fixed';
					connectionIndicator.style.bottom = '10px';
					connectionIndicator.style.right = '10px';
					connectionIndicator.style.backgroundColor = '#4CAF50';
					connectionIndicator.style.color = 'white';
					connectionIndicator.style.padding = '5px 10px';
					connectionIndicator.style.borderRadius = '4px';
					connectionIndicator.style.fontSize = '12px';
					connectionIndicator.style.zIndex = '1000';
					connectionIndicator.style.opacity = '0.8';
					connectionIndicator.textContent = 'SSE Connected';

					// Remove after 3 seconds
					setTimeout(() => {
						if (document.body.contains(connectionIndicator)) {
							document.body.removeChild(connectionIndicator);
						}
					}, 3000);

					document.body.appendChild(connectionIndicator);

				} catch (error) {
					console.error('Error parsing test event data:', error, event.data);
				}
			});

			// Initialize a Set to track displayed tool calls
			if (!window.displayedToolCalls) {
				window.displayedToolCalls = new Set();
			}

			// Handle tool call events
			eventSource.addEventListener('toolCall', (event) => {
				// If no request is in progress, ignore the tool call
				if (!isRequestInProgress) {
					console.log('Tool call received but no request in progress, ignoring');
					return;
				}
				console.log('%c Received tool call event:', 'background: #4CAF50; color: white; padding: 2px 5px; border-radius: 2px;', event);
				try {
					const toolCall = JSON.parse(event.data);
					console.log('%c Tool call data:', 'background: #2196F3; color: white; padding: 2px 5px; border-radius: 2px;', toolCall);

					// Skip events with status "started" - only process "completed" events
					if (toolCall.status === "started") {
						console.log('%c Skipping "started" event, waiting for "completed"', 'background: #FF9800; color: white; padding: 2px 5px; border-radius: 2px;');
						return;
					}

					// Create a unique identifier for this tool call
					const query = toolCall.args.query || toolCall.args.keywords || toolCall.args.pattern || '';
					const path = toolCall.args.path || toolCall.args.folder || '.';

					// Create a simpler fingerprint that doesn't include timestamp
					// This helps catch duplicate events with different timestamps
					const toolCallFingerprint = `${toolCall.name}-${query}-${path}`;

					// Check if we've already displayed this exact tool call
					if (window.displayedToolCalls.has(toolCallFingerprint)) {
						console.log(`%c Skipping duplicate tool call: ${toolCallFingerprint}`, 'background: #FF9800; color: white; padding: 2px 5px; border-radius: 2px;');
						return;
					}

					// Add this tool call to our set of displayed tool calls
					window.displayedToolCalls.add(toolCallFingerprint);
					console.log(`%c Added tool call to displayed set: ${toolCallFingerprint}`, 'background: #9C27B0; color: white; padding: 2px 5px; border-radius: 2px;');

					// Format the tool call description for display
					let toolDescription = '';
					if (toolCall.name === 'searchCode' || toolCall.name === 'search') {
						const language = toolCall.args.language;
						const exact = toolCall.args.exact;

						let locationInfo = path !== '.' ? ` in ${path}` : '';
						let languageInfo = language ? ` (language: ${language})` : '';
						let exactInfo = exact === true ? ` (exact match)` : '';

						toolDescription = `Searching code with "${query}"${locationInfo}${languageInfo}${exactInfo}`;
					} else if (toolCall.name === 'queryCode' || toolCall.name === 'query') {
						toolDescription = `Querying code with pattern "${query}"${path === '.' ? '' : ` in ${path}`}`;
					} else if (toolCall.name === 'extractCode' || toolCall.name === 'extract') {
						const filePath = toolCall.args.file_path || '';
						const line = toolCall.args.line;
						const endLine = toolCall.args.end_line;

						let lineInfo = '';
						if (line && endLine) {
							lineInfo = ` (lines ${line}-${endLine})`;
						} else if (line) {
							lineInfo = ` (from line ${line})`;
						}

						toolDescription = `Extracting code from ${filePath}${lineInfo}`;
					} else {
						toolDescription = `Using ${toolCall.name} tool`;
					}

					// Log the tool call being processed
					console.log(`%c Processing tool call: "${toolDescription}"`, 'background: #9C27B0; color: white; padding: 2px 5px; border-radius: 2px;');

					// Add tool call to the current AI message if it exists
					if (currentAiMessageDiv) {
						addToolCallToMessage(currentAiMessageDiv, toolCall);
					} else {
						console.warn('No current AI message div to add tool call to');
						// Create a temporary div to display the tool call
						const tempDiv = document.createElement('div');
						tempDiv.className = 'ai-message';
						tempDiv.innerHTML = '<div class="tool-call-header">Tool call received but no message context</div>';
						messagesDiv.appendChild(tempDiv);
						addToolCallToMessage(tempDiv, toolCall);
					}
				} catch (error) {
					console.error('Error parsing tool call data:', error, event.data);
				}
			});

			// Handle errors
			eventSource.onerror = (error) => {
				console.error('%c SSE Error:', 'background: #F44336; color: white; padding: 2px 5px; border-radius: 2px;', error);

				// Log detailed readyState information
				const readyStateMap = {
					0: 'CONNECTING',
					1: 'OPEN',
					2: 'CLOSED'
				};
				const readyState = eventSource.readyState;
				console.log(`EventSource readyState: ${readyState} (${readyStateMap[readyState] || 'UNKNOWN'})`);

				// Check if the connection was established before the error
				if (readyState === 2) {
					console.log('Connection was closed. Attempting to reconnect...');
				} else if (readyState === 0) {
					console.log('Connection is still trying to connect. Will retry if it fails.');
				}

				// Try to reconnect after a delay
				console.log('Will attempt to reconnect in 5 seconds...');
				setTimeout(connectToToolEvents, 5000);
			};

			// Add open event handler
			eventSource.onopen = () => {
				console.log('%c SSE connection opened successfully', 'background: #4CAF50; color: white; padding: 2px 5px; border-radius: 2px;');
				console.log('Ready to receive tool call events for session:', sessionId);
			};
		}

		// Add tool call to the AI message
		function addToolCallToMessage(messageDiv, toolCall) {
			console.log('%c Adding tool call to message:', 'background: #4CAF50; color: white; padding: 2px 5px; border-radius: 2px;', toolCall);

			try {
				// Format the tool call description for display
				let toolDescription = '';
				if (toolCall.name === 'searchCode' || toolCall.name === 'search') {
					const query = toolCall.args.query || toolCall.args.keywords || '';
					const path = toolCall.args.path || toolCall.args.folder || '.';
					const language = toolCall.args.language;
					const exact = toolCall.args.exact;

					let locationInfo = path !== '.' ? ` in ${path}` : '';
					let languageInfo = language ? ` (language: ${language})` : '';
					let exactInfo = exact === true ? ` (exact match)` : '';

					toolDescription = `Searching code with "${query}"${locationInfo}${languageInfo}${exactInfo}`;
				} else if (toolCall.name === 'queryCode' || toolCall.name === 'query') {
					const query = toolCall.args.query || toolCall.args.pattern || '';
					const path = toolCall.args.path || toolCall.args.folder || '.';
					toolDescription = `Querying code with pattern "${query}"${path === '.' ? '' : ` in ${path}`}`;
				} else if (toolCall.name === 'extractCode' || toolCall.name === 'extract') {
					const filePath = toolCall.args.file_path || '';
					const line = toolCall.args.line;
					const endLine = toolCall.args.end_line;

					let lineInfo = '';
					if (line && endLine) {
						lineInfo = ` (lines ${line}-${endLine})`;
					} else if (line) {
						lineInfo = ` (from line ${line})`;
					}

					toolDescription = `Extracting code from ${filePath}${lineInfo}`;
				} else if (toolCall.name === 'searchFiles') {
					const pattern = toolCall.args.pattern || '';
					const directory = toolCall.args.directory || '.';
					toolDescription = `Searching for files matching "${pattern}"${directory !== '.' ? ` in ${directory}` : ''}`;
				} else if (toolCall.name === 'listFiles') {
					const directory = toolCall.args.directory || '.';
					const pattern = toolCall.args.pattern || '';
					toolDescription = `Listing files${pattern ? ` matching "${pattern}"` : ''}${directory !== '.' ? ` in ${directory}` : ''}`;
				} else {
					toolDescription = `Using ${toolCall.name} tool`;
				}

				// Create a simple paragraph element with the formatted description
				const paragraph = document.createElement('p');
				paragraph.textContent = toolDescription;
				paragraph.style.fontStyle = 'italic';
				paragraph.style.color = '#555';
				paragraph.style.margin = '8px 0';

				// Add the paragraph to the message div
				messageDiv.appendChild(paragraph);

				// Scroll to the bottom
				messagesDiv.scrollTop = messagesDiv.scrollHeight;

				console.log('%c Tool call added successfully', 'background: #4CAF50; color: white; padding: 2px 5px; border-radius: 2px;');
			} catch (error) {
				console.error('Error adding tool call to message:', error);
			}
		}
		// Connect to tool events on page load
		window.addEventListener('DOMContentLoaded', () => {
			// Check if we're in no API keys mode
			const noApiKeys = document.body.getAttribute('data-no-api-keys') === 'true';

			if (!noApiKeys) {
				connectToToolEvents();
			}
		});

		// Handle "New chat" button click
		document.addEventListener('DOMContentLoaded', () => {
			const newChatLink = document.querySelector('.new-chat-link');
			if (newChatLink) {
				newChatLink.addEventListener('click', (e) => {
					e.preventDefault();

					// Cancel any ongoing requests for the current session
					cancelRequest(sessionId).catch(err => console.error('Error cancelling session on new chat:', err));

					// Generate a new session ID
					sessionId = crypto.randomUUID();
					console.log(`New chat started in current window. New session ID: ${sessionId}`);

					// Update URL to reflect new session
					updateUrlForSession(sessionId);

					// Make session ID available to other scripts
					// We use both direct property assignment and event dispatch for compatibility
					window.sessionId = sessionId;

					// Dispatch an event with the session ID for any external scripts that may be listening
					window.dispatchEvent(new MessageEvent('message', {
						data: { sessionId: sessionId }
					}));

					// Clear the messages
					messagesDiv.innerHTML = '';

					// Reset the UI
					positionInputForm();
					searchSuggestionsDiv.style.display = 'block';

					// Hide and reset token usage display
					const tokenUsageElement = document.getElementById('token-usage');
					if (tokenUsageElement) {
						tokenUsageElement.style.display = 'none';

						// Reset token usage counters
						document.getElementById('current-request').textContent = '0';
						document.getElementById('current-response').textContent = '0';
						document.getElementById('total-request').textContent = '0';
						document.getElementById('total-response').textContent = '0';
					}

					// Close existing SSE connection and reconnect with new session ID
					if (eventSource) {
						eventSource.close();
					}
					connectToToolEvents();

					// Send a request to the server to clear the chat history for this session
					fetch('/chat', {
						method: 'POST',
						headers: { 'Content-Type': 'application/json' },
						body: JSON.stringify({
							message: '__clear_history__',
							sessionId,
							clearHistory: true
						})
					}).catch(err => console.error('Error clearing chat history:', err));
				});
			}
		});

		// Add event listener for page unload to cancel the current session
		window.addEventListener('beforeunload', () => {
			// If we have a sessionId that's about to become invalid, cancel it
			if (sessionId) {
				// Use navigator.sendBeacon for more reliable delivery during page unload
				const data = JSON.stringify({ sessionId });
				if (navigator.sendBeacon) {
					navigator.sendBeacon('/cancel-request', data);
				} else {
					// Fallback to fetch for older browsers
					fetch('/cancel-request', {
						method: 'POST',
						headers: { 'Content-Type': 'application/json' },
						body: data,
						// Use keepalive to ensure the request completes even if the page is unloading
						keepalive: true
					}).catch((err) => console.error('Error cancelling session on unload:', err));
				}
			}
		});

		// Controller for aborting fetch requests
		let currentController = null;
		// Flag to track if a request is in progress
		let isRequestInProgress = false;

		// Function to cancel the current request on the server
		async function cancelRequest(sessionId) {
			try {
				const response = await fetch('/cancel-request', {
					method: 'POST',
					headers: { 'Content-Type': 'application/json' },
					body: JSON.stringify({ sessionId })
				});

				if (response.ok) {
					console.log('Request cancelled successfully on server');
				} else {
					console.error('Failed to cancel request on server');
				}
			} catch (error) {
				console.error('Error cancelling request:', error);
			}
		}

		// Handle form submission
		// Use the button click event instead of form submit to avoid potential form submission issues
		const searchButton = document.getElementById('search-button');
		searchButton.addEventListener('click', async (e) => {
			e.preventDefault();

			// If this is a stop action
			if (searchButton.textContent === 'Stop') {
				// Abort the current fetch request
				if (currentController) {
					currentController.abort();
					currentController = null;
				}

				// Send cancellation request to the server
				if (isRequestInProgress) {
					await cancelRequest(sessionId);
					isRequestInProgress = false;

					// Stop token usage polling when request is cancelled
					stopTokenUsagePolling();
				}

				// Reset the button to "Search" and enable input
				searchButton.textContent = 'Search';
				searchButton.style.backgroundColor = '#44CDF3';
				input.disabled = false;
				return;
			}

			const message = input.value.trim();
			if (!message) return;

			// Check if this is the first message
			const isFirstMessage = messagesDiv.children.length === 0;
			
			// Update URL for first message if we're on root path
			if (isFirstMessage && window.location.pathname === '/') {
				updateUrlForSession(sessionId);
			}

			// Display user message with proper image handling
			const userMsgDiv = document.createElement('div');
			userMsgDiv.className = 'user-message markdown-content'; // Add markdown-content class
			
			// Render the text message
			userMsgDiv.innerHTML = renderMarkdown(message);
			
			// Get uploaded images for display in user message
			const userMessageImages = window.getUploadedImagesForChat ? window.getUploadedImagesForChat() : [];
			
			// Add uploaded images if any
			if (userMessageImages.length > 0) {
				userMessageImages.forEach(imageUrl => {
					const imgElement = document.createElement('img');
					imgElement.src = imageUrl;
					imgElement.alt = 'Uploaded image';
					imgElement.style.maxWidth = '100%';
					imgElement.style.maxHeight = '300px';
					imgElement.style.borderRadius = '8px';
					imgElement.style.margin = '8px 0';
					imgElement.style.border = '1px solid #e0e0e0';
					imgElement.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.1)';
					imgElement.style.cursor = 'pointer';
					imgElement.style.transition = 'transform 0.2s ease';
					userMsgDiv.appendChild(imgElement);
				});
			}
			
			messagesDiv.appendChild(userMsgDiv);

			// Apply syntax highlighting to code blocks in user message
			userMsgDiv.querySelectorAll('pre code').forEach((block) => {
				hljs.highlightElement(block);
			});

			// Render Mermaid diagrams in user message
			const userMermaidDivs = userMsgDiv.querySelectorAll('.mermaid');
			if (userMermaidDivs.length > 0) {
				console.log(`Found ${userMermaidDivs.length} mermaid diagrams in user message`);
				try {
					if (typeof mermaid.run === 'function') {
						mermaid.run({ nodes: userMermaidDivs });
					} else if (typeof mermaid.init === 'function') {
						mermaid.init(undefined, userMermaidDivs);
					}
					// Convert rendered SVGs to PNGs
					setTimeout(() => {
						const renderedSvgs = userMsgDiv.querySelectorAll('.mermaid svg');
						if (renderedSvgs.length > 0) {
							renderedSvgs.forEach((svg, index) => {
								convertSvgToPng(svg, userMsgDiv, index);
							});
						}
					}, 100);
				} catch (error) {
					console.error('Error rendering mermaid in user message:', error);
				}
			}
			input.value = '';
			autoResizeTextarea(); // Reset textarea height after clearing content

			// If this is the first message, move the input form to the bottom and hide UI elements
			if (isFirstMessage) {
				positionInputForm();
				searchSuggestionsDiv.style.display = 'none';

				// Ensure footer is hidden when chat starts
				const footer = document.querySelector('.footer');
				if (footer) {
					footer.style.display = 'none';
				}

				// Show token usage display
				document.getElementById('token-usage').style.display = 'block';

				// Show token usage display
				const tokenUsageElement = document.getElementById('token-usage');
				if (tokenUsageElement) {
					tokenUsageElement.style.display = 'block';
				}

				// Keep the allowed folders section visible during chat
				// This is the key change - we don't hide the folder information anymore
			}

			// Create AI message container
			const aiMsgDiv = document.createElement('div');
			aiMsgDiv.className = 'ai-message markdown-content';

			// Store the original message for copying
			aiMsgDiv.setAttribute('data-original-markdown', '');

			// Add the AI message to the DOM
			messagesDiv.appendChild(aiMsgDiv);

			// Set as current AI message for tool calls
			currentAiMessageDiv = aiMsgDiv;

			// Disable input and change button to "Stop"
			input.disabled = true;
			searchButton.textContent = 'Stop';
			searchButton.style.backgroundColor = '#f44336';

			// Set request in progress flag
			isRequestInProgress = true;

			// Start token usage polling for long-running requests
			startTokenUsagePolling();

			// Send message to server
			try {
				// Log the session ID being used
				console.log(`%c Using session ID for chat request: ${sessionId}`, 'background: #FF9800; color: white; padding: 2px 5px; border-radius: 2px;');

				// Get API key from local storage if available
				const storedApiProvider = localStorage.getItem('probeApiProvider');
				const storedApiKey = localStorage.getItem('probeApiKey');
				const storedApiUrl = localStorage.getItem('probeApiUrl');

				// Get uploaded images as base64 data URLs
				const uploadedImageUrls = window.getUploadedImagesForChat ? window.getUploadedImagesForChat() : [];
				
				const requestData = {
					message: message, // Keep text separate from images
					images: uploadedImageUrls, // Send images separately
					sessionId, // Include session ID with the request
					apiProvider: storedApiProvider,
					apiKey: storedApiKey,
					apiUrl: storedApiUrl
				};
				
				if (uploadedImageUrls.length > 0) {
					console.log(`Including ${uploadedImageUrls.length} uploaded image(s) with message`);
				}
				console.log('Sending chat request with data:', requestData);

				// Add a visual indicator that we're using this session ID
				const sessionIndicator = document.createElement('div');
				sessionIndicator.style.position = 'fixed';
				sessionIndicator.style.top = '10px';
				sessionIndicator.style.right = '10px';
				sessionIndicator.style.backgroundColor = '#FF9800';
				sessionIndicator.style.color = 'white';
				sessionIndicator.style.padding = '5px 10px';
				sessionIndicator.style.borderRadius = '4px';
				sessionIndicator.style.fontSize = '12px';
				sessionIndicator.style.zIndex = '1000';
				sessionIndicator.style.opacity = '0.8';
				sessionIndicator.textContent = `Session ID: ${sessionId.substring(0, 8)}...`;

				// Remove after 3 seconds
				setTimeout(() => {
					if (document.body.contains(sessionIndicator)) {
						document.body.removeChild(sessionIndicator);
					}
				}, 3000);

				document.body.appendChild(sessionIndicator);

				// Create a new AbortController for this request
				currentController = new AbortController();
				const signal = currentController.signal;

				const response = await fetch('/chat', {
					method: 'POST',
					headers: {
						'Content-Type': 'application/json',
						'Cache-Control': 'no-cache',
						'Pragma': 'no-cache'
					},
					cache: 'no-store',
					body: JSON.stringify(requestData),
					signal: signal
				}).catch(error => {
					if (error.name === 'AbortError') {
						console.log('Fetch aborted');
						aiMsgDiv.innerHTML += '<p><em>Search was stopped by user.</em></p>';
						return null;
					}
					throw error;
				});

				// If response is null (aborted), reset UI and return
				if (!response) {
					// Reset button to "Search" and enable input
					form.querySelector('button').textContent = 'Search';
					form.querySelector('button').style.backgroundColor = '#44CDF3';
					input.disabled = false;
					return;
				}

				// We'll rely on polling and final fetch for token usage updates
				// No need to extract from headers as it's redundant

				const reader = response.body.getReader();
				const decoder = new TextDecoder();
				let aiResponse = '';

				while (true) {
					const { done, value } = await reader.read();
					if (done) break;
					const chunk = decoder.decode(value, { stream: true });
					aiResponse += chunk;

					try {
						// Parse the JSON response to extract the "response" field
						const jsonResponse = JSON.parse(aiResponse);
						const markdownContent = jsonResponse.response;

						// Update the original markdown attribute with just the markdown content
						aiMsgDiv.setAttribute('data-original-markdown', markdownContent);

						// Render markdown content
						aiMsgDiv.innerHTML = renderMarkdown(markdownContent);

						// Apply syntax highlighting to code blocks
						aiMsgDiv.querySelectorAll('pre code').forEach((block) => {
							hljs.highlightElement(block);
						});

						// Don't render mermaid diagrams during streaming - will render once at the end
						// This prevents premature rendering attempts that might fail

						messagesDiv.scrollTop = messagesDiv.scrollHeight;
					} catch (error) {
						console.error('Error processing response chunk:', error);

						// Check if it's a JSON parsing error or a markdown rendering error
						if (error instanceof SyntaxError) {
							// If it's a JSON parsing error, show a message about incomplete response
							aiMsgDiv.innerHTML = '<p><em>Receiving response...</em></p>';
						} else {
							// If it's a markdown rendering error, try to parse JSON but show raw content
							try {
								const jsonResponse = JSON.parse(aiResponse);
								aiMsgDiv.textContent = jsonResponse.response || aiResponse;
							} catch (jsonError) {
								// If JSON parsing fails, show the raw text
								aiMsgDiv.textContent = aiResponse;
							}
						}
					}
				}

				// Final render after all content is received
				setTimeout(() => {
					try {
						// Parse the complete JSON response
						const jsonResponse = JSON.parse(aiResponse);
						const markdownContent = jsonResponse.response;

						// Update token usage if available
						if (jsonResponse.tokenUsage && window.tokenUsageDisplay) {
							window.tokenUsageDisplay.update(jsonResponse.tokenUsage);
						}

						// Make sure the final content is set correctly
						aiMsgDiv.setAttribute('data-original-markdown', markdownContent);
						aiMsgDiv.innerHTML = renderMarkdown(markdownContent);

						// Apply syntax highlighting to code blocks
						aiMsgDiv.querySelectorAll('pre code').forEach((block) => {
							hljs.highlightElement(block);
						});

						// Specifically target mermaid diagrams in the current message
						const finalMermaidDivs = aiMsgDiv.querySelectorAll('.language-mermaid');

						if (finalMermaidDivs.length > 0) {
							console.log(`Final render: Found ${finalMermaidDivs.length} mermaid diagrams in current message`);

							// Log the content of the first diagram for debugging
							if (finalMermaidDivs[0]) {
								console.log('First diagram content:', finalMermaidDivs[0].textContent.substring(0, 100) + '...');
							}

							// Try direct rendering with specific nodes from current message
							if (typeof mermaid.run === 'function') {
								console.log('Using mermaid.run() for rendering');
								mermaid.run({
									nodes: finalMermaidDivs
								});
							} else if (typeof mermaid.init === 'function') {
								// Fallback to older mermaid versions
								console.log('Using mermaid.init() for rendering');
								mermaid.init(undefined, finalMermaidDivs);
							} else {
								console.error('No suitable mermaid rendering method found');
							}

							// Verify rendering success
							setTimeout(() => {
								// Update selector to find SVGs inside code.language-mermaid elements
								const renderedSvgs = aiMsgDiv.querySelectorAll('.language-mermaid svg, .mermaid svg');
								console.log(`Rendering verification: Found ${renderedSvgs.length} rendered SVGs`);

								// Convert SVGs to PNGs if any were rendered
								if (renderedSvgs.length > 0) {
									console.log('Converting SVGs to PNGs...');
									renderedSvgs.forEach((svg, index) => {
										convertSvgToPng(svg, aiMsgDiv, index);
									});
								}

								// Also add zoom functionality to any existing PNG images
								setTimeout(() => {
									const existingPngs = aiMsgDiv.querySelectorAll('.mermaid-png:not(.zoom-enabled)');
									if (existingPngs.length > 0) {
										console.log(`Adding zoom functionality to ${existingPngs.length} existing PNG images`);
										existingPngs.forEach((png) => {
											if (!png.parentElement.classList.contains('mermaid-container')) {
												const container = document.createElement('div');
												container.className = 'mermaid-container';

												const zoomIcon = document.createElement('div');
												zoomIcon.className = 'zoom-icon';
												zoomIcon.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line><line x1="11" y1="8" x2="11" y2="14"></line><line x1="8" y1="11" x2="14" y2="11"></line></svg>';

												zoomIcon.addEventListener('click', function (e) {
													e.stopPropagation();
													showDiagramDialog(png.src);
												});

												png.parentNode.insertBefore(container, png);
												container.appendChild(png);
												container.appendChild(zoomIcon);
												png.classList.add('zoom-enabled');
											}
										});
									}
								}, 200);
							}, 100);
						} else {
							console.log('No mermaid diagrams found in current message');
						}
					} catch (error) {
						console.warn('Final mermaid rendering error:', error);
						console.error('Error details:', error.message);
					}

					// Add copy button below the message after rendering is complete
					if (!aiMsgDiv.nextElementSibling || !aiMsgDiv.nextElementSibling.classList.contains('copy-button-container')) {
						// Create copy button container
						const copyButtonContainer = document.createElement('div');
						copyButtonContainer.className = 'copy-button-container';

						// Create copy button
						const copyButton = document.createElement('button');
						copyButton.className = 'copy-button';
						copyButton.innerHTML = `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M7 5C7 3.34315 8.34315 2 10 2H19C20.6569 2 22 3.34315 22 5V14C22 15.6569 20.6569 17 19 17H17V19C17 20.6569 15.6569 22 14 22H5C3.34315 22 2 20.6569 2 19V10C2 8.34315 3.34315 7 5 7H7V5ZM9 7H14C15.6569 7 17 8.34315 17 10V15H19C19.5523 15 20 14.5523 20 14V5C20 4.44772 19.5523 4 19 4H10C9.44772 4 9 4.44772 9 5V7ZM5 9C4.44772 9 4 9.44772 4 10V19C4 19.5523 4.44772 20 5 20H14C14.5523 20 15 19.5523 15 19V10C15 9.44772 14.5523 9 14 9H5Z" fill="#666"></path></svg>Copy`;

						// Add click event to copy button
						copyButton.addEventListener('click', function () {
							const markdown = aiMsgDiv.getAttribute('data-original-markdown');
							if (markdown) {
								// Copy just the markdown content, not the raw JSON
								navigator.clipboard.writeText(markdown).then(() => {
									// Visual feedback
									copyButton.textContent = 'Copied!';

									setTimeout(() => {
										copyButton.innerHTML = `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M7 5C7 3.34315 8.34315 2 10 2H19C20.6569 2 22 3.34315 22 5V14C22 15.6569 20.6569 17 19 17H17V19C17 20.6569 15.6569 22 14 22H5C3.34315 22 2 20.6569 2 19V10C2 8.34315 3.34315 7 5 7H7V5ZM9 7H14C15.6569 7 17 8.34315 17 10V15H19C19.5523 15 20 14.5523 20 14V5C20 4.44772 19.5523 4 19 4H10C9.44772 4 9 4.44772 9 5V7ZM5 9C4.44772 9 4 9.44772 4 10V19C4 19.5523 4.44772 20 5 20H14C14.5523 20 15 19.5523 15 19V10C15 9.44772 14.5523 9 14 9H5Z" fill="#666"></path></svg>Copy`;
									}, 2000);
								}).catch(err => {
									console.error('Failed to copy text: ', err);
									copyButton.textContent = 'Failed to copy';

									setTimeout(() => {
										copyButton.innerHTML = `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M7 5C7 3.34315 8.34315 2 10 2H19C20.6569 2 22 3.34315 22 5V14C22 15.6569 20.6569 17 19 17H17V19C17 20.6569 15.6569 22 14 22H5C3.34315 22 2 20.6569 2 19V10C2 8.34315 3.34315 7 5 7H7V5ZM9 7H14C15.6569 7 17 8.34315 17 10V15H19C19.5523 15 20 14.5523 20 14V5C20 4.44772 19.5523 4 19 4H10C9.44772 4 9 4.44772 9 5V7ZM5 9C4.44772 9 4 9.44772 4 10V19C4 19.5523 4.44772 20 5 20H14C14.5523 20 15 19.5523 15 19V10C15 9.44772 14.5523 9 14 9H5Z" fill="#666"></path></svg>Copy`;
									}, 2000);
								});
							}
						});

						// Add elements to the DOM
						copyButtonContainer.appendChild(copyButton);

						// Insert after the AI message
						if (aiMsgDiv.nextSibling) {
							messagesDiv.insertBefore(copyButtonContainer, aiMsgDiv.nextSibling);
						} else {
							messagesDiv.appendChild(copyButtonContainer);
						}
					}
				}, 500); // Increased timeout to ensure DOM is fully updated
			} catch (error) {
				console.error('Error:', error);
				const errorMsg = document.createElement('div');
				errorMsg.className = 'ai-message';
				errorMsg.textContent = 'Error occurred while processing your request.';
				messagesDiv.appendChild(errorMsg);
			} finally {
				// Fetch and update token usage after each chat interaction
				// Only if this is still the current session
				if (window.sessionId === sessionId && window.tokenUsageDisplay && typeof window.tokenUsageDisplay.fetch === 'function') {
					console.log('[TokenUsage] Fetching final token usage after request completion');
					window.tokenUsageDisplay.fetch(sessionId);
				}

				// Clear uploaded images after successful send
				if (window.clearUploadedImagesAfterSend) {
					window.clearUploadedImagesAfterSend();
				}

				// Reset button to "Search" and enable input
				searchButton.textContent = 'Search';
				searchButton.style.backgroundColor = '#44CDF3';
				input.disabled = false;
				currentController = null;
				isRequestInProgress = false;

				// Stop token usage polling when request is completed
				stopTokenUsagePolling();
			}

			messagesDiv.scrollTop = messagesDiv.scrollHeight;
		});

		// Use the updateTokenUsageDisplay function defined at the beginning of the script

		// Fetch token usage manually only for long-running requests
		// This helps avoid redundant polling for quick responses
		let tokenUsagePollingTimer = null;
		let pollingAttempts = 0;
		const MAX_POLLING_ATTEMPTS = 10;

		// Function to start polling for token usage updates
		function startTokenUsagePolling() {
			// Reset attempts counter
			pollingAttempts = 0;
			// Clear any existing timer
			if (tokenUsagePollingTimer) {
				clearInterval(tokenUsagePollingTimer);
			}

			// Start polling immediately to show token usage as soon as possible
			if (isRequestInProgress && sessionId && window.tokenUsageDisplay) {
				console.log('[TokenUsage] Starting token usage polling for request...');

				// Do an initial fetch right away
				window.tokenUsageDisplay.fetch(sessionId);

				// Poll every 3 seconds (reduced from 5 seconds for more responsive updates)
				tokenUsagePollingTimer = setInterval(() => {
					if (isRequestInProgress && sessionId && window.tokenUsageDisplay) {
						console.log('[TokenUsage] Polling for token usage updates...');
						window.tokenUsageDisplay.fetch(sessionId);

						// Increment attempts counter
						pollingAttempts++;

						// If we've reached the maximum number of attempts, slow down polling
						if (pollingAttempts >= MAX_POLLING_ATTEMPTS) {
							console.log('[TokenUsage] Reached maximum polling attempts, slowing down polling');
							clearInterval(tokenUsagePollingTimer);
							tokenUsagePollingTimer = setInterval(() => {
								if (isRequestInProgress && sessionId && window.tokenUsageDisplay) {
									console.log('[TokenUsage] Slow polling for token usage updates...');
									window.tokenUsageDisplay.fetch(sessionId);
								} else {
									clearInterval(tokenUsagePollingTimer);
									tokenUsagePollingTimer = null;
									console.log('[TokenUsage] Stopped slow polling - request completed');
								}
							}, 10000); // Slow down to every 10 seconds
						}
					} else {
						// Stop polling if request is no longer in progress
						clearInterval(tokenUsagePollingTimer);
						tokenUsagePollingTimer = null;
						console.log('[TokenUsage] Stopped polling - request completed');
					}
				}, 3000);
			}
		}

		// Function to stop polling
		function stopTokenUsagePolling() {
			if (tokenUsagePollingTimer) {
				clearInterval(tokenUsagePollingTimer);
				tokenUsagePollingTimer = null;
				console.log('[TokenUsage] Stopped token usage polling');
			}
		}

		const messageInput = document.getElementById('message-input');

		function autoResizeTextarea() {
			messageInput.style.height = 'auto'; // Reset to natural height
			const scrollHeight = messageInput.scrollHeight;
			messageInput.style.height = Math.min(scrollHeight, 200) + 'px'; // Set height, capped at 200px
		}

		// Initialize height on page load
		window.addEventListener('load', () => {
			autoResizeTextarea(); // Set initial height based on content (empty = min-height)
		});

		// Auto-resize as user types
		messageInput.addEventListener('input', autoResizeTextarea);

		// Handle Shift+Enter for new line and Enter for form submission
		messageInput.addEventListener('keydown', function (e) {
			if (e.key === 'Enter') {
				if (e.shiftKey) {
					// Allow new line with Shift+Enter and resize
					setTimeout(autoResizeTextarea, 0);
				} else {
					// Trigger search button click on Enter without Shift
					e.preventDefault();
					searchButton.click();
				}
			}
		});

		// API Key Form Functionality
		document.addEventListener('DOMContentLoaded', function () {
			// Check if API key is already stored
			const storedApiProvider = localStorage.getItem('probeApiProvider');
			const storedApiKey = localStorage.getItem('probeApiKey');
			const storedApiUrl = localStorage.getItem('probeApiUrl');

			const apiProviderSelect = document.getElementById('api-provider');
			const apiKeyInput = document.getElementById('api-key');
			const apiUrlInput = document.getElementById('api-url');
			const saveButton = document.getElementById('save-api-key');
			const headerResetButton = document.getElementById('header-reset-api-key');
			const statusDiv = document.getElementById('api-key-status');
			const apiKeySetupDiv = document.getElementById('api-key-setup');
			const inputForm = document.getElementById('input-form');

			// If API key is stored, show a success message and show the header reset button
			if (storedApiKey) {
				// Show the reset button in the header
				headerResetButton.style.display = 'inline-block';
				statusDiv.textContent = `API key for ${storedApiProvider} is configured`;
				statusDiv.className = 'api-key-status success';
				statusDiv.style.display = 'block';

				// Fill the form with stored values
				if (storedApiProvider) {
					apiProviderSelect.value = storedApiProvider;
				}
				if (storedApiKey) {
					apiKeyInput.value = '••••••••••••••••••••••••••';
				}
				if (storedApiUrl) {
					apiUrlInput.value = storedApiUrl;
				}

				// If we have an API key in local storage, always enable the chat interface
				// regardless of no API keys mode
				// Hide API key setup and show input form
				apiKeySetupDiv.style.display = 'none';
				inputForm.style.display = 'flex';

				// Remove API setup mode class
				document.body.classList.remove('api-setup-mode');
			}

			// Save API key to local storage
			saveButton.addEventListener('click', function () {
				const provider = apiProviderSelect.value;
				const key = apiKeyInput.value;
				const url = apiUrlInput.value;

				// Don't save if the key is masked
				if (key === '••••••••••••••••••••••••••') {
					statusDiv.textContent = 'No changes made to API key';
					statusDiv.className = 'api-key-status';
					statusDiv.style.display = 'block';
					return;
				}

				// Validate inputs
				if (!key) {
					statusDiv.textContent = 'Please enter an API key';
					statusDiv.className = 'api-key-status error';
					statusDiv.style.display = 'block';
					return;
				}

				// Save to local storage
				localStorage.setItem('probeApiProvider', provider);
				localStorage.setItem('probeApiKey', key);
				if (url) {
					localStorage.setItem('probeApiUrl', url);
				} else {
					localStorage.removeItem('probeApiUrl');
				}

				// Show success message
				statusDiv.textContent = `API key for ${provider} saved successfully`;
				statusDiv.className = 'api-key-status success';
				statusDiv.style.display = 'block';

				// Mask the API key for security
				apiKeyInput.value = '••••••••••••••••••••••••••';

				// If we're in no API keys mode, enable the chat interface
				if (document.body.getAttribute('data-no-api-keys') === 'true') {
					// Hide API key setup and show input form
					apiKeySetupDiv.style.display = 'none';
					inputForm.style.display = 'flex';

					// Refresh the page to apply changes
					setTimeout(() => {
						window.location.reload();
					}, 1000);
				}
			});

			// Reset API key from header button
			headerResetButton.addEventListener('click', function (e) {
				e.preventDefault();

				// Confirm before resetting
				if (confirm('Are you sure you want to reset your API key configuration?')) {
					// Remove from local storage
					localStorage.removeItem('probeApiProvider');
					localStorage.removeItem('probeApiKey');
					localStorage.removeItem('probeApiUrl');

					// Hide the reset button
					headerResetButton.style.display = 'none';

					// Show message
					alert('API key configuration has been reset.');

					// Reload the page
					window.location.reload();
				}
			});
		});

		// Image Upload Functionality
		(function() {
			// Global state to track uploaded images
			window.uploadedImages = window.uploadedImages || [];
			
			// Get DOM elements
			const imageUploadButton = document.getElementById('image-upload-button');
			const imageUploadInput = document.getElementById('image-upload');
			const messageInput = document.getElementById('message-input');
			const textareaContainer = document.querySelector('.textarea-container');
			const floatingThumbnails = document.getElementById('floating-thumbnails');

			// Image upload button click handler
			imageUploadButton.addEventListener('click', function() {
				imageUploadInput.click();
			});

			// File input change handler
			imageUploadInput.addEventListener('change', function(e) {
				const files = Array.from(e.target.files);
				handleImageFiles(files);
			});

			// Drag and drop functionality
			textareaContainer.addEventListener('dragover', function(e) {
				e.preventDefault();
				textareaContainer.classList.add('drag-over');
			});

			textareaContainer.addEventListener('dragleave', function(e) {
				e.preventDefault();
				textareaContainer.classList.remove('drag-over');
			});

			textareaContainer.addEventListener('drop', function(e) {
				e.preventDefault();
				textareaContainer.classList.remove('drag-over');
				
				const files = Array.from(e.dataTransfer.files).filter(file => 
					file.type.startsWith('image/')
				);
				
				if (files.length > 0) {
					handleImageFiles(files);
				}
			});

			// Clipboard paste functionality
			messageInput.addEventListener('paste', function(e) {
				const clipboardItems = e.clipboardData.items;
				const imageFiles = [];

				for (let i = 0; i < clipboardItems.length; i++) {
					const item = clipboardItems[i];
					if (item.type.startsWith('image/')) {
						const file = item.getAsFile();
						if (file) {
							imageFiles.push(file);
						}
					}
				}

				if (imageFiles.length > 0) {
					e.preventDefault(); // Prevent default paste behavior
					handleImageFiles(imageFiles);
				}
			});

			// Handle image files
			function handleImageFiles(files) {
				files.forEach(file => {
					// Validate file size (10MB limit)
					if (file.size > 10 * 1024 * 1024) {
						showImageError(`File "${file.name}" is too large (${(file.size / 1024 / 1024).toFixed(1)}MB). Maximum size is 10MB.`);
						return;
					}

					// Validate file type
					if (!file.type.startsWith('image/')) {
						showImageError(`File "${file.name}" is not a valid image file.`);
						return;
					}

					// Convert to base64 and add to uploaded images
					const reader = new FileReader();
					reader.onload = function(e) {
						const base64Data = e.target.result;
						const imageInfo = {
							id: Date.now() + Math.random(),
							name: file.name,
							size: file.size,
							type: file.type,
							base64: base64Data
						};

						window.uploadedImages.push(imageInfo);
						addImagePreview(imageInfo);
						updateThumbnailsVisibility();
					};

					reader.onerror = function() {
						showImageError(`Failed to read file "${file.name}".`);
					};

					reader.readAsDataURL(file);
				});
			}

			// Add image preview
			function addImagePreview(imageInfo) {
				const thumbnailItem = document.createElement('div');
				thumbnailItem.className = 'floating-thumbnail';
				thumbnailItem.dataset.imageId = imageInfo.id;

				thumbnailItem.innerHTML = `
					<img src="${imageInfo.base64}" alt="${imageInfo.name}">
					<button type="button" class="floating-thumbnail-remove" onclick="removeImagePreview('${imageInfo.id}')">×</button>
				`;

				floatingThumbnails.appendChild(thumbnailItem);
			}

			// Remove image preview
			window.removeImagePreview = function(imageId) {
				// Remove from uploaded images array
				window.uploadedImages = window.uploadedImages.filter(img => img.id != imageId);
				
				// Remove from DOM
				const thumbnailItem = document.querySelector(`[data-image-id="${imageId}"]`);
				if (thumbnailItem) {
					thumbnailItem.remove();
				}

				updateThumbnailsVisibility();
			};

			// Clear all images (internal function)
			function clearAllImages() {
				window.uploadedImages = [];
				floatingThumbnails.innerHTML = '';
				updateThumbnailsVisibility();
			}

			// Update thumbnails container visibility
			function updateThumbnailsVisibility() {
				if (window.uploadedImages.length > 0) {
					floatingThumbnails.style.display = 'flex';
				} else {
					floatingThumbnails.style.display = 'none';
				}
			}

			// Show image error
			function showImageError(message) {
				console.error('[Image Upload]', message);
				
				// Create error notification
				const errorDiv = document.createElement('div');
				errorDiv.style.position = 'fixed';
				errorDiv.style.top = '20px';
				errorDiv.style.right = '20px';
				errorDiv.style.backgroundColor = '#dc3545';
				errorDiv.style.color = 'white';
				errorDiv.style.padding = '12px 16px';
				errorDiv.style.borderRadius = '6px';
				errorDiv.style.zIndex = '9999';
				errorDiv.style.maxWidth = '300px';
				errorDiv.style.fontSize = '14px';
				errorDiv.textContent = message;

				document.body.appendChild(errorDiv);

				// Auto-remove after 5 seconds
				setTimeout(() => {
					if (errorDiv.parentNode) {
						errorDiv.parentNode.removeChild(errorDiv);
					}
				}, 5000);
			}

			// Function to get images as base64 data URLs for chat
			window.getUploadedImagesForChat = function() {
				return window.uploadedImages.map(img => img.base64);
			};

			// Function to clear images after successful send
			window.clearUploadedImagesAfterSend = function() {
				clearAllImages();
			};
		})();

		// Function to process message for display (handle base64 images)
		function processMessageForDisplay(message) {
			// Pattern to match base64 data URLs
			const base64ImagePattern = /data:image\/([a-zA-Z]*);base64,([A-Za-z0-9+/=]+)/g;
			
			// Replace base64 data URLs with proper img tags
			const processedMessage = message.replace(base64ImagePattern, (match, imageType, base64Data) => {
				// Estimate file size for display
				const estimatedSize = (base64Data.length * 3) / 4;
				const sizeText = estimatedSize > 1024 * 1024 
					? `${(estimatedSize / 1024 / 1024).toFixed(1)}MB`
					: `${(estimatedSize / 1024).toFixed(1)}KB`;
				
				// Create an image markdown with the base64 data
				return `![Uploaded image (${imageType}, ${sizeText})](${match})`;
			});
			
			return processedMessage;
		}

		// Make the function globally available
		window.processMessageForDisplay = processMessageForDisplay;

		// Add click-to-zoom functionality for images in messages
		document.addEventListener('click', function(e) {
			if (e.target.tagName === 'IMG' && (e.target.closest('.user-message') || e.target.closest('.ai-message'))) {
				e.preventDefault();
				showImageDialog(e.target.src, e.target.alt || 'Image');
			}
		});

		// Function to show image in full-screen dialog
		function showImageDialog(imageSrc, imageAlt) {
			// Create dialog overlay
			const overlay = document.createElement('div');
			overlay.style.position = 'fixed';
			overlay.style.top = '0';
			overlay.style.left = '0';
			overlay.style.width = '100%';
			overlay.style.height = '100%';
			overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
			overlay.style.zIndex = '10000';
			overlay.style.display = 'flex';
			overlay.style.alignItems = 'center';
			overlay.style.justifyContent = 'center';
			overlay.style.cursor = 'pointer';

			// Create image container
			const imageContainer = document.createElement('div');
			imageContainer.style.position = 'relative';
			imageContainer.style.maxWidth = '90%';
			imageContainer.style.maxHeight = '90%';

			// Create image element
			const img = document.createElement('img');
			img.src = imageSrc;
			img.alt = imageAlt;
			img.style.maxWidth = '100%';
			img.style.maxHeight = '100%';
			img.style.objectFit = 'contain';
			img.style.borderRadius = '8px';

			// Create close button
			const closeButton = document.createElement('button');
			closeButton.innerHTML = '×';
			closeButton.style.position = 'absolute';
			closeButton.style.top = '-10px';
			closeButton.style.right = '-10px';
			closeButton.style.width = '30px';
			closeButton.style.height = '30px';
			closeButton.style.borderRadius = '50%';
			closeButton.style.border = 'none';
			closeButton.style.backgroundColor = '#fff';
			closeButton.style.color = '#333';
			closeButton.style.fontSize = '18px';
			closeButton.style.cursor = 'pointer';
			closeButton.style.zIndex = '10001';

			// Add elements to DOM
			imageContainer.appendChild(img);
			imageContainer.appendChild(closeButton);
			overlay.appendChild(imageContainer);
			document.body.appendChild(overlay);

			// Close on overlay click or close button click
			overlay.addEventListener('click', function(e) {
				if (e.target === overlay || e.target === closeButton) {
					document.body.removeChild(overlay);
				}
			});

			// Close on escape key
			const escapeHandler = function(e) {
				if (e.key === 'Escape') {
					document.body.removeChild(overlay);
					document.removeEventListener('keydown', escapeHandler);
				}
			};
			document.addEventListener('keydown', escapeHandler);
		}
	</script>
</body>

</html>